RStudio interface - page 40

Control Flow - Introduction

Control flows connect several building blocks of your code together

Note: We will come back to the notion of ‘Algorithm’ in much more details in Week 7.

Control Flow - Instructions if and else - Page 117

x <- 3
y <- 2
if (x<=y) {
  print("x smaller than y")
  } else {
  print("x larger than y")
}
## [1] "x larger than y"

Control Flow - Instructions for - Page 119

for (i in m:n){}

x <- c(1,3,7,2)
for (i in 1:4){print(x[i])}
## [1] 1
## [1] 3
## [1] 7
## [1] 2
for (k in 2:4){
  x[k-1] <- x[k]
}
x
## [1] 3 7 2 2

Exercise: For loop

Suppose you open a new bank account. At time \(0\), you deposit \(\$500\) into your account. Your account earns \(i\%\) per annum of interest in year \(i\) (i.e. \(1\%\) in the first year, \(2\%\) in the second year, etc.)

What would be your account balance at the end of the 10th year? Use a ‘for’ loop in your solution.

Solution

balance <- 500
for (i in 1:10) {
  balance <- balance*(1 + i/100)
}
balance
## [1] 850.9107

Control Flow - Instructions while - Page 119

while (condition){}

x <- 2
y <- 1
while(x+y<6){
  x<-x+y
  print(x+y)}
## [1] 4
## [1] 5
## [1] 6
x
## [1] 5
# (x=2,y=1) -> (x+y=3<6) -> (x=3,y=1) -> (x+y=4<6) -> 
#(x=4,y=1) -> (x+y=5<6) -> (x=5,y=1) -> (x+y=6) -> End

Exercise: While loop

With the help of function rpois(n=1, lambda = 2), generate a series of random variables \(X_1, X_2, X_3, \ldots\) until one of them is equal to \(5\). Store those random variables and display the full sequence.

Solution

X <- rpois(n=1, lambda = 2) # We generate our first random variable
X.vector <- X # To start with, our sequence only contains one result (X)
while (X != 5) {
  X <- rpois(n=1, lambda = 2) # We generate a new random variable
  X.vector <- c(X.vector,X) # We add it to the sequence
}
X.vector
##  [1] 0 0 1 0 4 3 2 1 1 1 2 3 2 2 6 0 4 4 3 1 1 1 6 0 3 2 1 1 1 4 1 3 2 3 1 4 1 0
## [39] 2 2 2 3 2 3 0 0 3 2 1 3 0 6 3 3 1 1 0 2 3 0 0 4 2 1 5

Notes

Vectorization - Pages 85-86

x <- c(1,2,3)
y <- c(4,5,6)
x+y
## [1] 5 7 9
M <- matrix(1:9, nrow=3)
exp(M)
##           [,1]      [,2]     [,3]
## [1,]  2.718282  54.59815 1096.633
## [2,]  7.389056 148.41316 2980.958
## [3,] 20.085537 403.42879 8103.084

Vectorization - Example - Pages 86

x <- runif(5000000) # Generate 5 million random elements
z <- 0;
system.time(for(i in 1:5000000){z <- z + x[i]})
##    user  system elapsed 
##   0.073   0.000   0.073
z
## [1] 2500198
system.time(zz <- sum(x))
##    user  system elapsed 
##   0.008   0.000   0.008
zz
## [1] 2500198

Functions - calling functions - pages 43-44

functionname(arg1 = value1, arg2 = value2, arg3 = value3)

Functions - calling functions - page 44

Some functions don’t have arguments!

factorial(6)
## [1] 720
date()
## [1] "Mon Jun 19 02:03:04 2023"

Functions - Arguments - page 45

log(3)
## [1] 1.098612
log(x = 3)
## [1] 1.098612
log(x = 3, base = exp(1))
## [1] 1.098612
log(x = 3, exp(1))
## [1] 1.098612
log(3, base = exp(1))
## [1] 1.098612
log(3, exp(1))
## [1] 1.098612
log(base = exp(1), 3)
## [1] 1.098612
log(base = exp(1), x = 3)
## [1] 1.098612

Developing functions - Creating a function - Page 194

An important part of coding in R is creating your own functions.

Creating a function is done following the general syntax: function(<list of arguments>){<body of the function>}, where

Developing functions - Calling a function - Pages 194-195

To execute it, the user needs to call the function, followed by the effective arguments listed between brackets () and separated by commas. Here an effective argument is the value affected to a formal argument.

# This line creates a function called 'hello' with one argument called 'name'
hello <- function(name){cat("Hello, my dear", name, "!")}
# This line executes the function, with the the effective argument 'Josephine'
hello(name = "Josephine")
## Hello, my dear Josephine !

Note: R allows calling a function without typing in the complete name of a formal argument:

hello(na="Jinxia")
## Hello, my dear Jinxia !
hello(n="Samantha")
## Hello, my dear Samantha !

Developing functions - Body of a function - Page 195

Exercise - Page 195

Create a function hello() in R, such that

Target output

>hello("Peter")

Hello, my dear PETER !

Hint: Use function toupper().

Solution - Page 195

hello <- function(name){
  # Convert the name to upper case.
  name <- toupper(name)
  cat("Hello, my dear", name, "!")
  }

hello("Peter")
## Hello, my dear PETER !

Functions - Multiple arguments example

Of course, a function can have more than one argument. Here, function CDF.pois() has two arguments, x and lambda. It calculates the CDF \(F_X(x)\) at x of a Poisson random variable with parameter equal to lambda. Note the use of a for loop.

CDF.pois <- function(x, lambda){
  # Initialise the cdf to 0
  cdf = 0
  # For k from 0 to x, add together the probablity masses p(k)
  for (k in 0:x){
    cdf = cdf + exp(-lambda)*lambda^k/factorial(k)
  }
  # Return the result
  return(cdf)
}
CDF.pois(x = 3, lambda = 4)
## [1] 0.4334701

Note: we have every right to use a function within a function. For instance, here we used the (already defined) function factorial() inside our new function CDF.pois().

Functions - Exercise - pages 45-46

Code a function which takes two arguments \(n\) and \(p\) and calculates the binomial coefficient \[{n \choose p}=\frac{n!}{p!(n-p)!}\]

Test your function by evaluating the result of \[{5 \choose 3}\] which should yield \(10\).

Functions - Solution - pages 45-46

binomial <- function(n,p) {factorial(n)/(factorial(p)*factorial(n-p))}
binomial(5,3)
## [1] 10

Developing functions - Default argument values - Page 195

# Declare function 'binomial' with default values
binomial <- function(n=5,p=3){factorial(n)/(factorial(p)*factorial(n-p))}

binomial() # Use both default values
## [1] 10
binomial(n=6) # Specify first argument, but use default value for the second
## [1] 20

Developing functions - Object returned by a function - Pages 198-199

binomial <- function(n=5,p=3){
  return(factorial(n)/(factorial(p)*factorial(n-p)))
  # Everything below will not be executed, because we returned the first part
  my.unif <- runif(1)
  while (my.unif <= 1){ # Note that this part would be an infinite loop! Beware of those!
    my.unif <- runif(1)
  }
}

Developing functions - Variable scope in the body of a function - Page 200-201

Exercise

Create a function in R that calculates the present value of an annuity (paying \(1\) per year). The inputs are

Note: recall that the present value of an annuity that pays \(1\) at the end of each year for \(n\) years is \[\frac{1+(1+i)^{-n}}{i}.\] If payments occur at the beginning of the year (rather than in arrears), then the expected present value is \[(1+i)\frac{1+(1+i)^{-n}}{i}.\]

Solution

annuity_cal <- function(n=1, arrears=TRUE, i=0.06){
  discount <- 1/(1+i)
  temp <- (1-discount^n)/i
    if (arrears == T){
      return(temp)
    }
    else{ 
      return(temp*(1+i))
    }
}

annuity_cal()
## [1] 0.9433962
annuity_cal(a=FALSE)
## [1] 1
annuity_cal(n=5, a=FALSE, i=0.07)
## [1] 4.387211

Exercise

Create a function in R that plots the density/distribution function of a normal random variable. The arguments are

The output is either the density or the distribution function over the range \((\mu-4\sigma,\mu+4\sigma)\).

Hint: You will need functions dnorm() and pnorm() as well as function plot().

Note: There is more to come about graphical tools in Weeks 5.

Solution

plot_norm <- function(mean=0, variance=1, density=TRUE) {
  temp <- seq(from=mean-4*sqrt(variance), to=mean+4*sqrt(variance), by=sqrt(variance)/50)
  
  if (density) # Note writing 'if (density)' is equivalent to writing 'if (density = T)'
    plot(temp, dnorm(temp, mean, sqrt(variance)))
  else 
    plot(temp, pnorm(temp, mean, sqrt(variance)))
  }

plot_norm()

plot_norm(1,4,TRUE)

plot_norm(1,4,FALSE)