Install the package beepr and run the command beepr::beep(). beepr::beep(k) can play k=1-11 sounds. (See ?beep for a list of sounds).
A. Write loops and functions.
Write a loop to listen to each sound. Use Sys.sleep() to pause 2 seconds between each call to beep.
Modify the loop to pause a random duration of time. You can set your own parameters for ‘what a random duration of time’ means.
B. How can the beepr::beep() function be helpful? What does this say about R being a scripting language?
C. After calling library(beepr), the beep function can be directly called as beep(). Why can it be helpful to call beepr::beep()?
D. (If time allows) Create a function that takes two inputs: a numeric vector and sound. Write a loop that one-at-a-time calculates the cumulative sum each element of the vector (don’t use the cumsum function). Play a beep at the end of calculation using the sound input. The output should be a two-column matrix with the original vector (column 1) and the cumsum (column 2). Check you answer using the cumsum function.
Note: Question D is designed to practice working with loops and building up the output result. One-at-a-time calculations discouraged whenever avoidable. In practice, it would be better to use the cumsum function.
This week’s lesson
Focus on foundations
Many of the this week’s topics will be familiar, and it may be tempting to gloss over. However, there are important foundational concepts which can strengthen understanding and efficient coding.
Key concepts
In addition to general concepts, the below concepts are the essentials:
Creating and naming objects
Learn when each data structure is most useful
Develop habit to always use naming conventions to extract elements from objects
Creating loops
How-to create loops though use only as needed
Creating functions
How-to create functions
Use to reduce redundancy and increase clarity
Vectorized programming
Develop habit to vectorize whenever possible
R and RStudio
What is R?
R is an object oriented-, functional-, and scripting-programming language.
Data are stored in objects (vectors, matrixes, lists, data.frames) and manipulated using objects (functions).
Objects:
Are assigned a value via <- (preferred), =, or ->.
Have basic, intrinsic properties (aka attributes): mode (data type) and length
May have additional attributes such as (list from link)
class (a character vector with the classes that an object inherits from).
comment
dim (which is used to implement arrays)
dimnames
names (to label the elements of a vector or a list).
row.names
levels (for factors)
Have a class which may behave differently for generic functions (such as plot and summary) … we’ll discuss classes later.
The attributes of an object can be seen through str() and attributes():
data("HairEyeColor")HairEyeColor
, , Sex = Male
Eye
Hair Brown Blue Hazel Green
Black 32 11 10 3
Brown 53 50 25 15
Red 10 10 7 7
Blond 3 30 5 8
, , Sex = Female
Eye
Hair Brown Blue Hazel Green
Black 36 9 5 2
Brown 66 34 29 14
Red 16 7 7 7
Blond 4 64 5 8
# Example of base function (with R installation)1+1# Example of installed function from a packageinstall.packages("beepr")beepr::beep(0)# General structure of custom function< name of your function><-function(< argument 1>,< argument 2>=< default value >, ...,< argument n>) {< some R code here >return(< a single object of result(s) >)}
# Examples of custom functionfun1 <-function(v1,v2) {v1+v2}fun1(1,2)
# List with element names 1, 2, and 3x <-list("1"=1, "2"=2, "3"="A")x
$`1`
[1] 1
$`2`
[1] 2
$`3`
[1] "A"
# data.frameas.data.frame(x)
X1 X2 X3
1 1 2 A
Atomic modes
Back to modes … The 6 primitive modes are also called ‘atomic’ modes. This means that when data are stored together in a vector, they must be of the same mode.
When modes are mixed (ex: x <- c("A",0,1L,TRUE)), R will force all elements to be of the same mode.
Question: What is your guess for which modes receive greatest priority?
Missing values
R has different types of missing values (in order of most primitive):
NULL: which has length 0,
NaN: Not a Number
NA: no information, has length 1,
Inf: Infinite, and
These have companion functions is.na(), is.null, is.infinite (or is.finite(), which covers NA, Inf, and NaN), and is.nan.
Vectors and matrixes
Why to use vectors and matrices: they use less memory than lists and data.frame.
Get into a habit of using vectors and matrices / arrays as much as possible.
Creating vectors
To initialize an empty vector, use vector, rep(NA,<length>), numeric(<length>), or character(<length>).
(JC aside) When I use loops (later below) to iteratively calculate results, I use rep(NA,<length>) to ‘pre-allocate’ a vector to store results.
A question to keep in back of mind (we will revisit when talking about loops) … Why would you want to initialize an empty vector?
Other common methods to create numeric vectors include combine function, c(), :, seq, and rep:
# Combine 3 numeric vectors each with length 1c(1,2,3,4)> [1] 1234# Vector of sequential numericsx <-1:10x> [1] 12345678910# Vector of sequential numerics from 1 to length(x)seq(x)> [1] 12345678910# Vector of sequential numerics from 1 to 10 by 2seq(1,10,by=2)> [1] 13579# Vector of sequential numerics from 1 to 10 divided equally into 3 elementsseq(1,10,length.out=3)> [1] 1.05.510.0# Vector of repeated numericsrep(1:2,each=5)> [1] 1111122222# Vector of repeated numericsrep(1:2,times=5)> [1] 1212121212# Initialize an empty vector to 'pre-allocate' memory for future resultsout <-rep(NA,10)
Creating matrices
Three common ways to create matrices: matrix, cbind, rbind.
# Beware of dimension reductiondim(x[,c("SLC","Milcreek")])
[1] 2 2
dim(x["2010",c("SLC","Milcreek")])
NULL
In the last example, why is the dimension NULL? (Hint, what is the class of the last two examples?)
Questions 2: Naming objects
What is the number of the alphabet for each letter of your name? Use a vector with names (try the `LETTERS’ object). For example, if the letters to the name JONATHAN were mapped to integers, the result would be: 10, 15, 14, 1, 20, 8, 1, 14.
Why is it important extract elements through naming conventions?
Lists
Why to use lists?
Lists are useful for returning output from functions. For example, the output of lm is a list. (Aside, it is also of the class lm which has a specific behavior when calling “generic” functions such as print and summary).
How many vacations were taken on the first and ninth year?
How many total vacations were taken on odd years? Use element names for solution.
How many total vacations were taken on even years? Use the seq function for solution. (seq(2010,2020,by=2))
Why would you want to use element names whenever possible?
If/Then Statements, Loops, and Functions (Control Statements)
“R is a block-structured language … delineated by braces, though braces are optional if the block consists of just a single statement. Statements are separated by newline characters or, optionally, by semicolons.” (Matlooff, page 139)
If-then statements
Conditional logic evaluates
x <-"yes"if(x=="yes") {print("I'll take on the project") } else {print("Sorry, I can't take on the project")}> [1] "I'll take on the project"
The above if-else statement requires a single TRUE/FALSE evaluation. ifelse “vectorizes” conditional logic.
x <-seq(1:10)ifelse(test = x>5, yes =1, no =0)> [1] 0000011111
Loops
Loops iterate operations through a parameter saved in a vector. Possible loops include:
for: iterate through each value/element of a vector
while: continue loop while TRUE until FALSE
repeat: continue loop until a return or break statement
i <-1while (i <=10){ i <- i +4}i> [1] 13i <-1while(TRUE){i <- i +4if(i >10) break}i> [1] 13i <-1repeat{ i <- i +4if (i >10) break}i> [1] 13
The next statement allows the loop to stop current iteration and continue to next iteration.
Questions 4: Creating a loop
From Jan 1 - Jan 9, 2023, it snowed 6 days atop Snowbasin. Snow days can be represented each day in a vector as 1 (snow) and 0 (no snow).
snow <-c(1,1,1,1,0,1,1,0,0)names(snow) <-1:9
Suppose you are interested in the first day it consecutively snowed three days (i.e. snowed the given day and two previous days). What is this day? Solve using a loop with conditional logic.
Functions
Repeating the strengths of functions … Using functions is a major theme of good R programming. Avoid explicit iteration (loops and copy-paste) as much as possible. [Matloff (pg xxii)]:
Clearer, more compact code
Potentially must faster execution speed
Less debugging, because the code is simpler
Easier transition to parallel programming
In general terms, R functions are structured as follow:
< name of your function><-function(< argument 1>,< argument 2>=< default value >, ...,< argument n>) {< some R code here >return(< some result >)}
For example, if we want to create a function to run the “unfair coin experiment” we could do it in the following way:
# Function definition# unfairCoin# n: number of tosses# p: biased coin (default = 0.7)unfairCoin <-function(n, p =0.7) {# Sampling from the coin dist ans <-sample(c("H", "T"), n, replace =TRUE, prob =c(p, 1-p))# Returning ans}# Testing itset.seed(1)tosses <-unfairCoin(20)table(tosses)
tosses
H T
13 7
prop.table(table(tosses))
tosses
H T
0.65 0.35
Questions 5: Creating a function
Generalize your code to Question 4 as a function so that for any string of days you can find the first day it consecutively snowed a given number of days. Return NA if no day meets this criteria.
Vectorizing and replicate
R Simultaneously performs the same operation across vector elements.
Behind the scenes R calls C code to do one-at-a-time calculation, but this is faster than doing one-at-a-time calculation in R.
Key point: Loops carry out one-at-a-time operations. Usually, a vectorized alternative to loops is to use *apply functions.
The replicate() function in R is not strictly vectorized in the same way that functions like + or mean() are, as it involves iterating over a specified number of replications. However, it is a convenient function for repeating an expression or function multiple times and collecting the results.
“Urn 1 contains ten blue marbles and eight yellow ones. In urn 2, the mixture is six blue and six yellow. We draw a marble at random from urn 1, transfer it to urn 2, and then draw a marble at random from urn 2. What is the probability that that second marble is blue? This is easy to find analytically, but we’ll use simulation.” Create a function that generates 100K replicates and returns the estimated probability.