3 Simple programming

We often want to repeat specific operations several times. For example, we might want to repeat an operation for different elements of a given data structure, such as columns of a matrix, or perform an operation until a satisfactory result is reached, such as running an algorithm until the value converges to a prespecified level. In addition, we often need to check whether certain conditions are fulfilled, such as whether elements of a vector are equal to 0, and perform an operation depending on the result.

3.1 The for-loop

A for-loop is a procedure in which a particular routine is repeated and only an index variable is changed.

x=0
for (i in 1:3) { 
  x=x+i
  print(x)
}
## [1] 1
## [1] 3
## [1] 6

We can also use it to study the behavior of the arithmetic mean

out = rep(0,100)
n = 20
for (i in 1:100) { 
  x = rnorm(n, mean = 0,sd = 1)
  out[i]=mean(x)
}
mean(out)
## [1] -0.006733313
sd(out)
## [1] 0.2324998
out = rep(0,100)
n = 200
for (i in 1:100) { 
  x = rnorm(n,mean = 0,sd = 1)
  out[i]=mean(x)
}
mean(out)
## [1] -0.005580671
sd(out)
## [1] 0.06197756

3.2 The if-condition

Within a for-loop, it may be useful to perform arithmetic operations only under certain conditions. The basic syntax for this is

if (condition){
  statement  
  } 
else{
  alternative
  }

where else can remain unspecified.

###If-condition###
y <- c(1,4,5,2,7,8,2,4)
N <- length(y)
1:N
## 
y.sq <- numeric(N)#creates an empty numeric vector of length N

for(i in 1:N){ #initializing the for-loop
  y.sq[i] <- y[i]^2#every element of y.sq is replaced by the respective squared value.
  if(i == N){#only when this condition is met, i.e. in the last iteration of the loop 
    print(y.sq)#is the vector printed
  }
}

In shorter form the ifelse() command is an alternative.

ifelse(test, yes, no)

3.3 The while-loop

The while-loop performs a program (“statement”) as long as certain data conditions (“test expression”) are met. The basic syntax is

while (testexpression)
{
  #increment (i+1);
  statement
}

Here, test_expression is evaluated and the body of the loop is entered if the result is TRUE.

i <- 1

while (i < 6) {
  print(i)
  i = i+1
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

3.4 Time saving and loops

One easy way to make your loops in R faster is to preallocate space for your results instead of appending them to a vector. This is caused by the underlying architectural choice of R that is called copy-on-modify. In some cases it leads to your whole data being copied from one place in memory to another, when you simply wanted to append another value to your vector.

If you look at the following code fragments, the second one is about 70 to 80 times faster!

# The slow but simple way
time <- system.time(
  {results <- c() # empty vector
  for(i in 1:100000){
    results <- c(results, rnorm(1))
  }}  
)
print(time)
##    user  system elapsed 
##    8.58    1.11    9.83
# The right way to do it
time2 <- system.time(
  {results2 <- vector(mode = "double", length = 100000)
  for(i in 1:100000){
    results2[i] <- rnorm(1)  
  }} 
)
print(time2)
##    user  system elapsed 
##    0.06    0.00    0.07

If you can avoid a loop altogether and use vector operations instead, your code will will be even faster.

# The right way to do it
time3 <- system.time(
  {results3 <- rnorm(100000)
  } 
)
print(time3)
##    user  system elapsed 
##    0.02    0.00    0.00

Try to keep this in mind when designing your own code. In R this is one of the most frequent and easily avoidable reasons for why code is slow.

3.5 Exercises III

Exercise 1:

Write a for-loop that iterates over the numbers 6 to 14 and prints the cube of each number using print()

Exercise 2:

Write a while-loop that prints out standard random normal numbers (use rnorm()) but stops (breaks) if you get a number bigger than 1.

Exercise 3:

Using a for-loop simulate the flip a coin twenty times, keeping track of the individual outcomes (1 = heads, 0 = tails) in a vector that you preallocated.