See the Work Along - Loops, etc. for in-class exercises.

One of the most fundamental features of a programming language like C is the for loop, which permits iteration of a process over some index set. Iteration in R is a more complex issue for reasons i’ll explain, but it does contain the basic functions for loops and flow control.

The for loop

As a first example, compute the 12th Fibonnaci number, defined recursively by

\[F_n = F_{n-1} + F_{n-2}, \quad F_0 = 1,\; F_1 = 1\]

We’ll store the numbers in a numeric vector:

fib <- numeric(13)
fib[1] <- 1
fib[2] <- 1

Now fill out the next values, up to the index 13.

for(j in 3:13) {
  fib[j] <- fib[j-1] + fib[j-2]
}
fib
##  [1]   1   1   2   3   5   8  13  21  34  55  89 144 233

Everything in R is a function but it’s best to think of the for loop as a container for a sequence of commands.

Usually, you iterate over a sequence of integers, but you can also use other vectors.

double_letters <- character()
for(x in c("a", "b", "c")) {
  double_letters <- c(double_letters, paste(x,x))
}
double_letters
## [1] "a a" "b b" "c c"

Vectorization eliminates many loops

For a numeric sequence v, compute a new sequence in which the \(j^{th}\) entry is the sin of v[j].

Here is the for loop method.

set.seed(666)
v <- rnorm(25)
w <- numeric(length(v))
for(j in 1:25) {
  w[j] <- sin(v[j])
}
w
##  [1]  0.68406  0.90323 -0.34772  0.89722 -0.79845  0.68776 -0.96519
##  [8] -0.71911 -0.97558 -0.04202  0.83688 -0.98018  0.76087 -0.98887
## [15]  0.13372 -0.07575  0.75673  0.33810 -0.55007  0.70765 -0.63815
## [22] -0.92576  0.95476 -0.30749  0.03057

However, we know that R vectorizes operations; i.e., it automatically iterates numeric functions over numeric vectors, entry by entry.

z <- sin(v)
z
##  [1]  0.68406  0.90323 -0.34772  0.89722 -0.79845  0.68776 -0.96519
##  [8] -0.71911 -0.97558 -0.04202  0.83688 -0.98018  0.76087 -0.98887
## [15]  0.13372 -0.07575  0.75673  0.33810 -0.55007  0.70765 -0.63815
## [22] -0.92576  0.95476 -0.30749  0.03057

Value of vectorization:
* simplicity of programming,
* speed

Computing on a long vector

set.seed(555)
v2 <- rnorm(10000000)

Compute the exponential of each entry.

w2 <- numeric(10000000)
system.time(
  for(j in 1:10000000) {
    w2[j] <- exp(v2[j])
  }
  )
##    user  system elapsed 
##  18.781   0.043  18.825

Try the vectorized method.

system.time(z2 <- exp(v2))
##    user  system elapsed 
##   0.080   0.000   0.081

The speed-up due to vectorization is dramatic. This is because vectorization codes the iteration step in C. This is the real advantage of vectorization.

Later, we’ll discuss methods of iterating operations over lists and rows or columns of matrices and data.frames. These are extremely useful in working with large datasets.

Other flow control

R has a while function as well as a for function. This allows iterations of flexible length.

while(expression) { code block}

should be read as

while the expression is true, iteratively execute the code block and re-evaluate the expression based on the result.

Conditional execution in R

The syntax of the if function in R is

if(expression) { code block}

which is executed as “if the expression is TRUE, execute the code block, otherwise skip it”.

This is handy when the code block can only be executed when some condition holds.

There is also an if else combination.

if(expression) { code block}
else {other code block}