class: clear, center, middle background-image: url(http://static1.squarespace.com/static/57d161dc20099eb4bb0ccc05/t/57d69e61414fb51a88bd4798/1523877244472/) background-size: contain --- # Intro .font120[ Often, we need to execute repetitive code statements a particular number of times. Or, we may even need to execute code for an undetermined number of times until a certain condition no longer holds. ] -- * .font130[`for`] loops: execute code for a prescribed number of times (Rule of 👍, 3x). * .font130[`while`] & .font130[`repeat`] loops: repeat code while condition holds * .font130[`next`] & .font130[`break`]: additional clauses to control flow -- <br> .center.bold[R is a vectorized and functional programming language, which minimizes the use of loops. You will learn alternative iterating options in the functional programming module; however, you still should understand the basics of loops.] --- # `for` loop: syntax .pull-left[ .font120[ * For each element in sequence (1-100) perform some defined task ] ] .pull-right[ ```r for(i in 1:100) { <do stuff here with i> } ``` ] --- # `for` loop: syntax .pull-left[ * For each element in sequence (1-100) perform some defined task * .red[What will this .font120[`for`] loop do?] ] .pull-right[ ```r for(i in 1:100) { <do stuff here with i> } ``` ```r for (i in 2010:2017) { print(paste("The year is", i)) } ``` ] --- # `for` loop: syntax .pull-left[ * For each element in sequence (1-100) perform some defined task * What will this .font120[`for`] loop do? * .red[`i` takes on the value of the numbers in the sequence] ] .pull-right[ ```r for(i in 1:100) { <do stuff here with i> } ``` ```r for (i in 2010:2017) { print(paste("The year is", i)) } ## [1] "The year is 2010" ## [1] "The year is 2011" ## [1] "The year is 2012" ## [1] "The year is 2013" ## [1] "The year is 2014" ## [1] "The year is 2015" ## [1] "The year is 2016" ## [1] "The year is 2017" ``` ] --- # `for` loop: sequence input .pull-left[ * Often, the length of the sequence is determined by some pre-defined variable * For example, say we have a variable .font120.blue[`x`] and we want to iterate over each element and do something * We can do this two ways ] .pull-right[ ```r *x <- 2010:2017 # option 1 for(i in 1:length(x)) { <do stuff here with x[i]> } # option 2 for(i in seq_along(x)) { <do stuff here with x[i]> } ``` ] <br> .center.bold.red[Talk to your neighbor. Do you prefer one over the other?
<img src="https://emojis.slackmojis.com/emojis/images/1504806416/2885/thinking-face-rotating.gif?1504806416" style="height:2em; width:auto; "/>
] --- # `for` loop: sequence input .pull-left[ * Often, the length of the sequence is determined by some pre-defined variable * For example, say we have a variable .font120.blue[`x`] and we want to iterate over each element and do something * We can do this two ways * But `seq_along(x)` is safer for edge cases where the sequence has length zero ] .pull-right[ ```r x <- c() # option 1: executes although it shouldn't for(i in 1:length(x)) { print(i) } ## [1] 1 ## [1] 0 # option 2: does not execute for(i in seq_along(x)) { print(i) } ``` ] <br> .center.bold.red[Beware iterating over `1:length(x)`. This will fail in unhelpful ways if `x` has length 0] --- # `for` loop: generating output .pull-left[ * Often we are generating output from the `for` loop that we want to use later * We can do this by either .bold.red[growing] or .bold.green[filling] the output * Pre-allocating the output and .bold.green[filling] in the results is more efficient ] .pull-right[ .code70[ ```r # Let's create 100 different vectors w/10,000 obs means <- seq(0, 100, by = 1) # Growing the output out <- list() system.time({ for(i in seq_along(means)) { # generate data gen_data <- rnorm(10000, means[[i]]) # grow list output out <- c(out, gen_data) } }) ## user system elapsed ## 0.612 0.151 0.764 # Pre-allocating and filling out <- vector("list", length(means)) system.time({ for(i in seq_along(means)) { # generate & fill output out[[i]] <- rnorm(10000, means[[i]]) } }) ## user system elapsed ## 0.067 0.000 0.066 ``` ] ] --- class: yourturn # Your Turn: Challenge * We can see all data sets that we have in the "data" folder with `list.files()` .code70[ ```r list.files("data") ## [1] "Month-01.csv" "Month-02.csv" "Month-03.csv" "Month-04.csv" ## [5] "Month-05.csv" "Month-06.csv" "Month-07.csv" "Month-08.csv" ## [9] "Month-09.csv" "Month-10.csv" "Month-11.csv" ``` ] .pull-left[ * Say we wanted to import one of these files into R ```r # here's a single file (first_df <- list.files("data")[1]) ## [1] "Month-01.csv" # create path and import this single file df <- readr::read_csv(paste0("data/", first_df)) # create a new name for file (new_name <- stringr::str_sub(first_df, end = -5)) ## [1] "Month-01" # dynamically rename file assign(new_name, df) ``` ] -- .pull-right[ * Can you incorporate these procedures into a `for` loop to import all the data files? ```r for(i in _____) { # 1: import data df <- readr::read_csv(_____) # 2: remove ".csv" of name new_name <- _____ # 3: dynamically rename file assign(_____, _____) } ``` ] --- class: yourturn # Your Turn: Solution .pull-left[ 1. Import ith data file 2. Make a new name without ".csv" (i.e. "Month-01") 3. Dynamically rename file with `assign()` 4. Remove unnecessary duplicate ] .pull-right[ ```r for(i in list.files("data")) { # 1: import data df <- readr::read_csv(paste0("data/", i)) # 2: remove ".csv" of name new_name <- stringr::str_sub(i, end = -5) # 3: dynamically rename file assign(new_name, df) # 4: remove unnecessary object rm(df) } # we have imported 11 files ls(pattern = "Month") ## [1] "Month-01" "Month-02" "Month-03" "Month-04" "Month-05" "Month-06" ## [7] "Month-07" "Month-08" "Month-09" "Month-10" "Month-11" ``` ] --- # Controlling sequences .pull-left[ There are two ways to control the progression of a loop: .font120[ * `next`: terminates the current iteration and advances to the next. ] ] .pull-right[ ```r x <- c(1, 2, NA, 3) # use next to skip an iteration for (i in x) { * if (is.na(i)) next # if NA don't execute print(i) } ## [1] 1 ## [1] 2 ## [1] 3 ``` ] --- # Controlling sequences .pull-left[ There are two ways to control the progression of a loop: * `next`: terminates the current iteration and advances to the next. * `break`: exits the entire `for` loop. ] .pull-right[ ```r x <- c(1, 2, NA, 3) # use next to skip an iteration for (i in x) { if (is.na(i)) next print(i) } ## [1] 1 ## [1] 2 ## [1] 3 ``` ```r # use break to stop for (i in x) { * if (is.na(i)) break # if NA stop! print(i) } ## [1] 1 ## [1] 2 ``` ] -- .center.red[_both are used in conjunction with `if` statements_] --- # Warning
<i class="fas fa-exclamation-triangle faa-FALSE animated " style=" color:red;"></i>
Note that `break` and `next` only control the progression of the .red.bold[direct] loop environment they are in. .pull-left[ .center[Break out of inner loop only] ```r x <- 1:3 y <- c("a", "b", NA) for(i in x) { print(i) for(j in y) { * if(is.na(j)) break # break out of inner loop print(j) } } ## [1] 1 ## [1] "a" ## [1] "b" ## [1] 2 ## [1] "a" ## [1] "b" ## [1] 3 ## [1] "a" ## [1] "b" ``` ] .pull-right[ .center[Stop entire process.] ```r x <- 1:3 y <- c("a", "b", NA) for(i in x) { print(i) for(j in y) { * if(is.na(j)) stop("break in inner loop") print(j) } } ## [1] 1 ## [1] "a" ## [1] "b" ## Error in eval(expr, envir, enclos): break in inner loop ``` .center.font80.red[You'll learn more about `stop()` in the functions module!] ] --- class: yourturn # Your Turn: Challenge! .pull-left[ The following code identifies the month of the data set: ```r # data files (data_files <- list.files("data")) ## [1] "Month-01.csv" "Month-02.csv" "Month-03.csv" "Month-04.csv" ## [5] "Month-05.csv" "Month-06.csv" "Month-07.csv" "Month-08.csv" ## [9] "Month-09.csv" "Month-10.csv" "Month-11.csv" # extract month number as.numeric(stringr::str_extract(data_files, "\\d+")) ## [1] 1 2 3 4 5 6 7 8 9 10 11 ``` ] -- .pull-right[ Modify the following `for` loop with a `next` or `break` statement to: 1. only import `Month-01` through `Month-07` 2. only import `Month-08` through `Month-10` ```r # Modify this code chunk with you next/break statement for(i in list.files("data")) { # steps to import each data set df <- readr::read_csv(paste0("data/", i)) new_name <- stringr::str_sub(i, end = -5) assign(new_name, df) rm(df) } ``` ] --- class: yourturn # Your Turn: Solution! .pull-left[ .center[\#1: only import `Month-01` through `Month-07`] ```r for(i in list.files("data")) { * # break if month is greater than 7; although * # this requires knowledge of month order * month <- as.numeric(stringr::str_extract(i, "\\d+")) * if(month > 7) break # steps to import each data set df <- readr::read_csv(paste0("data/", i)) new_name <- stringr::str_sub(i, end = -5) assign(new_name, df) rm(df) } # we've only imported months 1-7 ls(pattern = "Month") ## [1] "Month-01" "Month-02" "Month-03" "Month-04" "Month-05" "Month-06" ## [7] "Month-07" ``` ] .pull-right[ .center[\#2: only import `Month-08` through `Month-10`] ```r for(i in list.files("data")) { * # skip importing file if month value is not 8-10 * month <- as.numeric(stringr::str_extract(i, "\\d+")) * if(month < 8 | month > 10) next # steps to import each data set df <- readr::read_csv(paste0("data/", i)) new_name <- stringr::str_sub(i, end = -5) assign(new_name, df) rm(df) } # we've only imported months 1-7 ls(pattern = "Month") ## [1] "Month-08" "Month-09" "Month-10" ``` ] --- # Repeating code for undefined number of iterations Sometimes we need to execute code for an undetermined number of times until a certain condition no longer holds. Two very similar options: -- .pull-left[ .center.bold[while loop] ```r while(condition) { <do stuff> } ``` <div style="height:15px;font-size:15px;"> </div> * Test condition first * Then execute code ] -- .pull-right[ .center.bold[repeat loop] ```r repeat { <do stuff> if(condition) break } ``` * Execute code first * Then test condition ] --- # Repeating code for undefined number of iterations The probability of flipping 10 coins and getting all heads or tails is `\((\frac{1}{2})^{10} = 0.0009765625\)` (1 in 1024 tries). How quickly can we achieve this accomplishment? .pull-left[ .center[Using `while`] ```r coin <- c("heads", "tails") n_tries <- 0 flip <- NULL while(length(unique(flip)) != 1) { # flip coin 10x flip <- sample(coin, 10, replace = TRUE) # add to the number of tries n_tries <- n_tries + 1 } n_tries ## [1] 33 ``` ] .pull-right[ .center[Using `repeat`] ```r coin <- c("heads", "tails") n_tries <- 0 repeat { # flip coin 10x flip <- sample(coin, 10, replace = TRUE) # add to the number of tries n_tries <- n_tries + 1 # if current flip contains all heads or tails break if(length(unique(flip)) == 1) { print(n_tries) break } } ## [1] 213 ``` ] --- class: yourturn # Your Turn: Challenge! .pull-left[ An elementary example of a random walk is the random walk on the integer number line, `\(\mathbb {Z}\)` , which starts at 0 and at each step moves +1 or −1 with equal probability. See if you can do a random walk starting at 0, with each step either adding or subtracting 1. Have you random walk stop if it exceeds 100 or if the number of steps taken exceeds 10,000. ] -- .pull-right[ Fill in this incomplete code chunk: ```r value <- 0 step <- 0 repeat { # randomly add or subtract 1 # count step # break once our walk exceeds 100 if(some_condition) { print(step) break } } ``` ] --- class: yourturn # Your Turn: Solution! .pull-left[ This example reached 100 in 5,666 steps ```r value <- 0 step <- 0 repeat { # randomly add or subtract 1 random_step <- sample(c(-1, 1), 1) value <- value + random_step # count step step <- step + 1 # break once our walk exceeds 100 if(value == 100 | step > 10000) { print(step) break } } ## [1] 5666 ``` ] -- .pull-right[ What does a random walk look like? This example never reached 100. <img src="day-2b-loops_files/figure-html/unnamed-chunk-31-1.png" style="display: block; margin: auto;" /> In fact, it looks a little like the current stock market, eh? .center[
<img src="https://emojis.slackmojis.com/emojis/images/1502933663/2802/homer_scream.jpg?1502933663" style="height:2em; width:auto; "/>
] ] --- # Summary .font90[ * .font130[`for`] loops: execute code for a prescribed number of times (Rule of 👍, 3x). * .font130[`while`] & .font130[`repeat`] loops: repeat code while condition holds * .font130[`next`] & .font130[`break`]: additional clauses to control flow ] -- .font90[ * You can rewrite any `for` loop to use `while` instead, and you can rewrite any `while` loop to use `repeat`, but the converses are not true. * That means `while` is more flexible than `for`, and `repeat` is more flexible than `while`. ] .font110[ * It's good practice to use the least-flexible (or more strict) solution to a problem, which means that you should use `for` where possible. ] -- .font90[ * Generally speaking you can minimize the use of `for` loops in R since it is a vectorized and functional programming language. * Next you will learn about functional programming, which provides an even less flexible solution to most problems ] --- # Questions <br> <img src="images/questions.png" width="450" height="450" style="display: block; margin: auto;" />