This lab focuses on iterations (for loops, while loops, etc), simulations, and importing userdefined functions. Much of this comes from the R for Data Science edition online text https://r4ds.had.co.nz/iteration.html https://r4ds.hadley.nz/iteration.html, conversations with CS faculty, and my experience (i.e. learn from my mistakes).

Directions (Please read before starting)

  1. Please work together with your assigned partner. Make sure you both fully understand each concept before you move on.
  2. Please record your answers and any related code for all embedded lab questions. I encourage you to try out the embedded examples, but you shouldn’t turn them in.
  3. Please ask for help, clarification, or even just a check-in if anything seems unclear.

\(~\)

Preamble

Packages and Datasets

library(dplyr)
library(ggplot2)

\(~\)

Iterations

Iterations are used when you are continuously repeating the same operation(s) on different values that are known in advance. Like functions, utilizing iterations helps to reduce code space and errors.

  • Imperative Loops:
    • For Loops
    • While Loops
    • Contents:
      • Sequence (what you iterate over)
      • Body (What you do)
      • (output) (what you return, not always explicit)
  • Functionals:
    • In R you can call functions within functions.
    • You could also turn a loop into a general function and then call the function
    • map functions: loop over a vector, do something, save the results
      • map() makes a list. There is a map_X() for every standard data type x
      • input: vector, function
      • output: vector where the function has been applied to every input
      • map() comes from the purrr package (written in c: faster but less legible)
    • Base R equivalent: lapply

Example 1: For loop

for (i in 1:5){#Sequence, for every i in the range 1:5 do
  print(i) #Body: Print i
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

Example 2: While loop

i=1
while (i <6){#Sequence, while i is < 6
  print(i) #Body: Print i, increment i
  i=i+1
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

\(~\)

Lab

At this point you should begin working with your partner. This lab will continue building on the fundamental aspects of R introduced previously. The lab’s examples will continue using the “Happy Planet” data, so please make sure you include code to load it.

\(~\)

Part 0: Importing User-Defined Functions

We discussed in Lab 14 that one of the advantages of user-defined functions is that we can reuse them in future projects. However, we didn’t discuss how to actually do that. In order to reuse functions, the best practice is to save them in an r script and then import them using source().

Question 1 Copy the exampleFunction3, zScore, and squaredError functions from Lab 14 to a new r script titled Lab14Functions.R saved in the same location as this lab. demonstrate that it worked by running the following code:

source("Lab14Functions.R")
zScore(c(1,2,4))
## [1] -0.8728716 -0.2182179  1.0910895

Part 1: Loops

  • There are 4 types of loops you will generally use in R:
    • For Loops
      • Modifying an existing object
      • Looping over names instead of indices
    • While Loops
      • Handling outputs of unknown length
      • Handling sequences of unknown length
  • There are 3 basic ways to loop over a vector:
    • Loop over indices (e.g. i in 1:10)
    • Loop over elements
    • Loop over names

The following example uses the “cars” dataset and each of the 3 loops are demonstrated

cardata<-cars
print(head(cardata))
##   speed dist
## 1     4    2
## 2     4   10
## 3     7    4
## 4     7   22
## 5     8   16
## 6     9   10
cardata2<-cars
#Loop over indices
for (i in 1:2){
  cardata2[,i]<-cardata2[,i]*5
}
print(head(cardata2))
##   speed dist
## 1    20   10
## 2    20   50
## 3    35   20
## 4    35  110
## 5    40   80
## 6    45   50
#loop over names
cardata3<-cars
for (col in colnames(cardata3)){
  cardata3[,col]<-cardata3[,col]*5
}
print(head(cardata3))
##   speed dist
## 1    20   10
## 2    20   50
## 3    35   20
## 4    35  110
## 5    40   80
## 6    45   50
#Loop over elements: difficult to save elements efficiently
cardata4<-cars
for (val in cardata4){
  print(val[1:6]*5)
}
## [1] 20 20 35 35 40 45
## [1]  10  50  20 110  80  50

\(~\)

Question 2 Using the Diamonds dataset and a for loop, rescale all numeric values to the range [0,1]. Notes: Carat is numeric, Cut is not. I don’t care which of the standard ways to normalize/rescale data you use as long as you are consistent. DO NOT write or use a built in function to rescale the values.

\(~\)

Question 3 Which is more general: A while loop or a for loop? That is, can you rewrite any for loop as a while loop? Any while loop as a for loop? Both can always be rewritten as the other, or neither can be guaranteed to be rewritten as the other.

If you claim that one type can be rewritten as the other type: Give me a series of steps do follow that work.

If you claim that one type can not be rewritten as the other type: give me an example that would fail.

\(~\)

Part 2: lapply

  • input: vector/list, function
  • output: list where the function has been applied to every input

Example from Lab 14. Instead of using the for loop, I could’ve used the lapply function. As you can see, it takes fewer lines and is more readable.

x1 <- c(1,2,3, "four", 5, "six", 7, 6, 2) #base vector. Expected output: 6 8 7
x2 <- c(3, 7, "four", 2) #HW 1 vector. Expected output: 8
x3 <- c("a","b","c") #No Numbers. Expected output: None
x4 <- c(1,2,3,8,9,10) #All integers, none that should be printed (both above and below). Expected output: None
x5 <- c(4,5,6,7) #All integers, all should be printed. Expected output: 6 7 8
x6 <- c(1,2,3,4,5,6,7,8,9,10) #All integers, some should be printed. Expected output: 6 7 8
x7 <- c(5.1,4.1,3.9,7.1,6.8,55/10,75/10) #Non integer numbers. Expected output: 6.1 5.1 7.8 6.5
testVectors<-list(x1,x2,x3,x4,x5,x6,x7)

lapply(testVectors,exampleFunction3)
## [[1]]
## [1] 6 8 7
## 
## [[2]]
## [1] 8
## 
## [[3]]
## numeric(0)
## 
## [[4]]
## numeric(0)
## 
## [[5]]
## [1] 6 7 8
## 
## [[6]]
## [1] 6 7 8
## 
## [[7]]
## [1] 6.1 5.1 7.8 6.5

another example

x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
# compute the list mean for each list element
lapply(x, mean)
## $a
## [1] 5.5
## 
## $beta
## [1] 4.535125
## 
## $logic
## [1] 0.5

\(~\)

Question 4 Using the Diamonds dataset. Write a function to calculate the mean absolute cubed difference of the values in the numeric columns when compared to the mean. (i.e. calculate the mean by column, subtract the mean from each value, take the absolute third power, take the mean of the column) . Then use lapply() to test your function.

As an example, your number for carat should match the below:

lapply(diamonds,q4Func)$carat
## [1] 0.1876116

\(~\)

Part 3: Simulation

References: - https://pubs.wsb.wisc.edu/academics/analytics-using-r-2019/simulation-basics.html - https://web.stanford.edu/class/bios221/labs/simulation/lab_3_simulation.html

Simulation in Statistics/Data Science is the use of computer simulations rather than collected data. This can be useful in a number of circumstances including estimating a p value. This is especially useful when collecting data or calculating a probability via the underlying distribution is complicated.

Theory:

  • Law of Large Numbers: (STA 209)
    • If you’ve forgotten this, the wiki article is useful https://en.wikipedia.org/wiki/Law_of_large_numbers
    • Given a sample of independent and identically distributed values, the sample mean converges to the true mean.
    • As long as a finite expected value exists for the underlying distribution, in the long run sample average converges to the expected value
  • Central Limit Theorem: (STA 209?)
  • Overall:
    • We know that a large sample should have the same mean as the expected value of the underlying distribution (LLN)
    • We know that repeated sample means should be normally distributed (CLT)
    • Therefore we can simulate multiple samples and analyze the distribution of the results using the statistical methods we have for normal distributions

Running a Simulation:

  • Assumptions:
    • Choice of Distribution
    • Choice of Parameters within the distribution
  • Good Practice:
    • Set a seed

\(~\)

For example, how likely is it that I flip at least 700 heads out of 1000 coin flips of a weighted coin that comes up heads 65% of the time?

Note: so as to not use an explicit loop, I will be using the “replicate” function in R which is a wrapper of the “lapply” function (above)

set.seed(0) #set the seed to 0 for replicability
prob_heads=0.65 #65% probability of heads
x=replicate(10000, #Replicate the simulation 10,000 times
            sum(runif(1000)<=prob_heads)) #simulate 1000 head flips of the weighted coin

Let’s look at the plot

ggplot(data.frame(x),aes(x=x))+
  geom_histogram() +
  theme_minimal()

It doesn’t look like there are very many cases where this is true. In fact, when we check directly with our simulation, we see that approximately 0.06% of the time would we expect 700 or more heads.

sum(x>=700)/10000
## [1] 6e-04

\(~\)

Proof of the use of the seed: 100% of x and y should match, minimal x and z should match.

set.seed(0) #set the seed to 0 for replicability
prob_heads=0.65 #65% probability of heads
y=replicate(10000, #Replicate the simulation 10,000 times
            sum(runif(1000)<=prob_heads)) #simulate 1000 head flips of the weighted coin
sum((x==y)==TRUE,na.rm=TRUE)/10000
## [1] 1
z=replicate(10000, #Replicate the simulation 10,000 times
            sum(runif(1000)<=prob_heads)) #simulate 1000 head flips of the weighted coin
sum((x==z)==TRUE,na.rm=TRUE)/10000
## [1] 0.0179

\(~\)

You can also run simulations with multiple underlying datasets.

Question 5 Determine the likelihood of winning the following game:

  • Roll a die, then flip a coin (assume 6 sided fair die, 2 sided fair coin)
  • If the die is 5 or 6, or the coin is heads you win
  • You play this game with your friend 100 times. What percent of the games would you expect to win

Part a Using Simulation with the following parameters:

  • Seed of 2024
  • 1000 replications
  • hint: use sample on the vector c(1:6)

Part b Using what you remember from STA 209, calculate it directly.

Part c Are these values the same? If not, are they close? (within 1%)