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)
\(~\)
library(dplyr)
library(ggplot2)
\(~\)
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.
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
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
\(~\)
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.
\(~\)
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
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.
\(~\)
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
\(~\)
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:
Running a Simulation:
\(~\)
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:
Part a Using Simulation with the following parameters:
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%)