For every fruit there is a loop ... i.e., more on control flow

The code we produced in class this week can be downloaded and reviewed here: Code-Day09.R and Code-Day10.R.

This week’s problem set and extra-credit opportunity can be found here:

The big new concept or construct discussed this week was the for-loop. Similar to the if and else constructs, the for-loop allows us to control the flow of operations in R. Whereas the if and else construct allows us to get the computer to do one thing if some condition is TRUE and another thing if the condition is FALSE, the for-loop construct allows us to instruct the computer to repeat a task or calculation as set number of times. This works like so:

# define object.o as a sequence of integers

object.o <- 1:10

for (element.i in object.o) {	
	# do something like say
	print("Hello") # or
	print(element.i) # or
	Sys.sleep(time = 2) # go to sleep for 2 seconds
}

The above code will instruct the computer to repeat the tasks of printing "Hello", printing an element.i from the object.o, and sleeping for 2 seconds, 10 times each.

We can use these for-loop constructs for all sorts of tasks that need to be repeated a certain number of times. Say, I need 10 random numbers. We could do the following:

rnorm(n = 10, mean = 0, sd = 1) # returns 10 random numbers 
			 	# as one vector.

Or we could instruct R to give us 1 random number 10 times in a row.

for (i in 1:10) {
	x <- rnorm(n = 1, mean = 0, sd = 1)
	print(x)
}			 	

If we ask R to do something once for every element i in a sequence of integers say 1:10, we can use the fact that the is are integers to index vectors and store output in specific locations of some vector. This might look something like this.

x <- rep(NA, times = 10) # initiate an empty vector

for (i in 1:10) {
	x[i] <- sample(x = letters, size = 1, replace = TRUE)
}

In the above code we asked R to pick one random letter from the alphabet (the object letters) and store the random letter in the ith location of the empty NA vector x. At the end of the loop the vector x will contain 10 random letters.

Another use for loops might be the creation of counters (in combination with if and else constructs).

Suppose we wanted to count the number of even numbers in some vector of integers. A for-loop can help solve this problem.

random.integers <- sample(x = 1:1000, size = 100, replace = TRUE)

# initiate two counters and set them to zero

even.counter <- 0
odd.counter <- 0

for (i in 1:100) {

	if (random.integers[i] %% 2 == 0) {

		even.counter <- even.counter + 1

	} else {

		odd.counter <- odd.counter + 1

	}

}

even.counter
odd.counter

During class on Wednesday we also reviewed the creation of functions by way of revisiting Problem Set 3. A set of possible responses is reproduced below.

Consider two examples:

The min

my_min <- function(input) {

	output <- sort(x = input, decreasing = FALSE)
	return(output)

}

# test my_min() and compare to min() 

x <- 10:1
y <- c(0, 1, -1)
z <- rnorm(n = 10, mean = 0, sd = 1)

min(x= x)
min(x= y)
min(x= z)

my_min(input = x)
my_min(input = y)
my_min(input = z)

The mean

my_mean <- function(input) {

	ouput <- sum(x = input)/length(x = input)
	return(output)

}

Even vs. odd

even <- function(input) {

	output <- ifelse(test = input %% 2 == 0, 
			  yes = "even",
			   no = "odd")
	return(output)

}

Absolute value (Version 1)

my_abs <- function(input) {

	output <- ifelse(test = input < 0,
		 	  yes = input * -1, 
		 	   no = input)
	return(output)

}

Absolute value (Version 2)

my_abs <- function(input) {

	output <- sqrt(x = input^2)
	return(output)

}

Median

# this version depends on the even() function above

my_median <- function(input) {

	n <- length(x = input)
	x <- sort(x = input)

	if (even(input = n) == "even") {

		return(mean(x = x[n/2, n/2 + 1]))

	} else {

		return(x[ceiling(x = n/2)])

	}

}

# test my_median() on even and odd length inputs 
# and compare to median() 

x <- rnorm(n = 100)
y <- rnorm(n = 101)

median(x = x)
my_median(input = x)

median(x = y)
my_median(input = y)