################################################################################ ### R BASICS WORKSHOP ### ### PRESENTATION 9: FLOW CONTROL ### ### ### ### Center for Conservation and Sustainable Development ### ### Missouri Botanical Garden ### ### Website: rbasicsworkshop.weebly.com ### ################################################################################ ################################################################################ ### 1. LOOPS: *while* ########################################################## ################################################################################ # *while* is also a very useful way to construct loops. This kind of loop # repeats a piece of code while a particular condition is TRUE. # The general structure of a *while* loop is: # # while(condition) # { # code # } # This translates approximately to: # # while condition is TRUE, repeat: # { # this code # } #################### ## Easy example 1 ## #################### v <- 1:10 i <- 0 # Version 1 while(i < max(v)) { i <- i+1 print(i) } #################### ## Easy example 2 ## #################### Bp <- 0.1 Dp <- 0.12 Np <- 1-Bp-Dp max.t <- 50 time <- 0 abund <- 10 plot(x=c(0, max.t), y=c(0, 100), type="n", xlab="Time", ylab="Abundance") while(abund>0 & time<=max.t) { change <- sample(c(-1,0,1), size=abund, prob=c(Dp, Np, Bp), replace=TRUE) abund <- abund + sum(change) time <- time + 1 points(time, abund, pch=16, cex=1, col="grey65") } ################################################################################ ### 2. CONDITIONALS: *if* ###################################################### ################################################################################ # The conditional *if* allows you to run a piece of code only if a condition is # TRUE #################### ## Easy example 1 ## #################### v <- 1:10 for(i in v) { print(i) if(i == 5) { print("Reached 5") } } #################### ## Easy example 2 ## #################### ## THE WHILE DATING LOOP ## you <- runif(1, 0, 100) # Your personality in a number your.pickiness.score <- 0.1 # How closely you want your date # to match your personality missmatch <- Inf # The initial difference in personality date <- 0 # Your date number while(missmatch > your.pickiness.score) { date <- date + 1 they <- runif(1, 0, 100) missmatch <- abs(you - they) if(missmatch <= your.pickiness.score) { print("Congratulations, you are getting married!!") print(paste("You've dated", date, "people", sep=" ")) } } ################################################################################ ### 3. BREAKS: *break* ######################################################### ################################################################################ # The function *break* causes a loop to stop. Breaks are frequently used in # combination with a conditional *if*. #################### ## Easy example 1 ## #################### v <- 1:10 for(i in v) { print(i) if(i == 5) # With more than one command, it is necessary to use *{}* { print("Reached 5") break() } } #################### ## Easy example 2 ## #################### Bp <- 0.1 Dp <- 0.12 Np <- 1-Bp-Dp max.t <- 50 time <- 0 abund <- 10 plot(x=c(0, max.t), y=c(0, 100), type="n", xlab="Time", ylab="Abundance") for(i in 1:max.t) { change <- sample(c(-1,0,1), size=abund, prob=c(Dp, Np, Bp), replace=TRUE) abund <- abund + sum(change) time <- time + 1 if(abund<=0) { warning("Population has gone extinct") break() } if(sum(change) > 0) COL <- "red" if(sum(change) < 0) COL <- "blue" if(sum(change) == 0) COL <- "grey65" points(time, abund, pch=16, cex=1, col=COL) } ################################################################################ ### 4. AVOIDING LOOPS ########################################################## ################################################################################ # Loops are extremely useful constructs in R, however they can be slow. If you # are having problems with scripts that take too long to run, it is a good idea # to vectorize: avoid loops and use pre-existing functions in R that work on # vectors. # A blog describing vectorization: # http://www.noamross.net/blog/2014/4/16/vectorization-in-r--why.html ## Easy example 1 ## x <- seq(1, 10, length.out=10000000) # Unvectorized version lsum <- 0 for(i in 1:length(x)) { lsum <- lsum + log(x[i]) } lsum # Vectorized version lsum <- sum(log(x)) lsum ## Easy example 2 ## # Lets assume we have a very large matrix of abundances of 50 species across # 1,000,000 sites M <- matrix(rpois(50000000, 10), ncol=50) dim(M) head(M) # How can we calculate the total abundance of individuals at each site? ## Option 1 - a very inefficient loop ## abund.1 <- numeric() # This creates a numeric vector of length 0 # system.time will help us calculate the time something takes system.time( { for(i in 1:nrow(M)) { abund.1 <- c(abund.1, sum(M[i,])) } }) ## Option 2 - a slightly better loop by initializing the vector that ## stores the results ## abund.2 <- rep(NA, nrow(M)) # This creates a vector of the needed length but # full of NAs system.time( { for(i in 1:nrow(M)) { abund.2[i] <- sum(M[i,]) } }) ## Option 3 - using the function *apply* hides the loop but does not help ## system.time( { abund.3 <- apply(M, 1, sum) }) ?apply ## Option 4 - a fully vectorized version ## system.time( { abund.4 <- rowSums(M) })