Chapter R Programming
Chapter R Programming
3
R programming
The R system is not only an interactive tool for exploring data sets and
graphic representations, but it also serves as an excellent environment for
programming. Comparably speaking, the programming syntax of R is easy
to learn. Users even without previous programming experience can get
started quickly in a couple of hours of learning some basic R control struc-
tures. This is exactly what we will do here. This chapter covers some basic
programming skills, focused on the use of flow controls and on how to write
functions for simple statistical problems.
• The if-statement
1 In recent versions of R, length-one numeric values also work, where zero corresponds
• The ifelse-statement
• The switch-function
QQ : No match!
a : 1
A : 1
bb : No match!
• The for-loop
3.1.3 Vectorization
Loops are very inefficiently implemented in R. So, the use of loops should
be avoided, whenever possible, and the technique of vectorization should be
used instead. Consider exam scores of five persons, which are represented
by s < −c(80, 45, 55, 90, 75). Let g be a vector grade, the element of which
is given the value 0 (”Fail”) if the score is less than 60 and 1 (”Pass”)
46 3. R programming
+ }
> sq3(5)
[1] 25
Note that a single expression can be entered directly on the same line of
the function keyword (as in sq1 and sq2). However, if there are several
expressions or statements to execute, they must be entered at different lines,
enclosed in braces (as in sq3). Also note that the above three functions are
all vectorized. (Test them for yourself: if x<-1:10, what will be the outputs?)
soning, given parameter B, we use the conditional probability Pr (A|B) to reason about
outcome A. In a backward reasoning, however, outcome A is given and the likelihood
function L(B|A) is used to reason about parameter B. Formally, a likelihood function
is a conditional probability function considered as a function of its second argument,
with its first argument held fixed, and also any other function proportional to such a
function. Thus, the likelihood function for B is the equivalence class of functions
L (b|A) = α Pr (A|B = b)
for any constant of proportionality α > 0.
48 3. R programming
+ return(like)
+}
Now, assume that there are 20 data points from a normal distribution
with the variance approximately being 1.0. The likelihood values for varying
values of the mean (i.e., from -2 to 2 with an increment of 0.1) is calculated
as:
> y=c(1.18,-0.84,-0.07,-2.00,-0.34,-1.84,-0.38,-2.39,-1.18,
+ 0.44,-0.21,0.43,-1.21,0.28,-1.19,0.19,-1.17,0.01)
> mean(y)
[1] -0.5716667
> mmu<-seq(-2,2,0.1)
> lkmu<-likemu(vmu=mmu,yobs=y)
In Figure 3.1, the maximum likelihood value is observed at a location
approximately correspond to the sample mean (µ ≈ −0.57). Think what
this result implies.
> plot(mmu,lkmu,type=’’h’’)
2.5e-11
2.0e-11
1.5e-11
lkmu
1.0e-11
5.0e-12
0.0e+00
-2 -1 0 1 2
mmu
FIGURE 3.1. Plot of likelihood values for a grid of mean values with the variance
fixed at 1.0
50 3. R programming
- 0 .5
-1 .0
-10 -5 0 5 10
FIGURE 3.2. Plots of a generic sin function for a specified set of x values
0
-5
y
-1 0
-1 5
-3 -2 -1 0 1 2
0 .5
0 .0
y
-0 .5
0 5 10 15 20
[1] 0
> 5 %m% 6
[1] 24
Next, a binary operation is defined for plotting y over x. Practically, y
can be a numeric vector, or any function of x. In Figure 3.4), for example,
we plot 0.3*cos(x) + 0.7*sin(2*x) over a grid of x values between 0.1 and
20.
> ’’%p%’’ <- function(y,x) plot(x, y, type=’’l’’, col=2)
> x <- seq(0.1, 20, length=400)
> (0.3*cos(x) + 0.7*sin(2*x)) %p% x
1! = 1 * 0! = 1 * 1 = 1
2! = 2 * 1! = 1 * 1 = 2
3! = 3 * 2! = 3 * 2 = 6
4! = 4 * 3! = 4 * 6 = 24
......
Here, we enter this function in another way. Use a text editor to enter
the following code.
factorial<-function (n) {
If (n==0) return(1)
else return(n*factorial(n-1))
}
Save this function as “factorial.R”, and load this function by source(’’factorial.R’’).
Now, it is ready for use.
> source(’’factorial.R’’)
> factorial(0)
[1] 1
> factorial(1)
[1] 1
> factorial(2)
[1] 2
> factorial(3)
[1] 6
> factorial(4)
[1] 24
> factorial(10)
[1] 3628800
print(w)
print(s1)
print(s2)
}
In this function, h and w are formal parameters, s1 is a local variable
and s2 is a free variable.
In R the value of a free variable is resolved by first looking in the en-
vironment in which the function was created. This is called lexical scope,
which marks one of the major differences between S-Plus and R. Lexical
scope can be confusing to R users, but, when probably use, it can provide a
powerful mechanism for controlling evaluation and it ensures that intended
sets of bindings between variables and values are used.
Define a function that calculates the volume of a cube.
cube <- function(w) {
area <- function() w * w
w * area()
}
The variable w is a formal parameter in the function cube, but it is
is a free variable in the function area, so its value is determined by the
scoping rules. In S-Plus, the value of w is that associated with a global
variable named w (i.e., static scope). In R, however, it is the parameter
to the function cube because that is the active binding for the variable
w at the time the function area was defined (i.e., lexical scope). So, the
difference is that S-Plus looks for a global variable called w while R first
looks for a variable called w in the environment created when cube was
invoked.
In S, suppose that there is a globe variable w=3. A call to cube(2) will
return 18 as the cube volumn.
S> cube(2)
Error in sq(): Object ’’w’’ not found
Dumped
S> w <- 3
S> cube(2)
[1] 18
In R, however, a call to the same function will return 8 as the answer.
> w<-3
> cube(2)
[1] 8
errors (which can be raised by a call to stop) and warnings (which can be
raised by a call to warning).
The typical behavior for an error is to halt the current evaluation and
return control to the top-level R prompt3 . The default behavior for warning
is to wait until the current evaluation is finished and, then, to print the
warning that occurred during the evaluation. Users can control the behavior
by making use of various R options, which is not discussed in details here.
Next is a simple example demonstrating the use of tryCatch for con-
ditionally evaluating expressions. In this example, two handlers are estab-
lished, one for errors and the other for warnings.
> foo <- function (x) {
+ if (x<3)
+ list() + x
+ else if (x<10)
+ warning(’’ouch’’)
+ else
+ 33
+ }
>
> foo(2)
Error in list() + x : non-numeric argument to binary operator
> foo(5)
Warning message:
In foo(5) : ouch
> foo(29)
[1] 33
>
> tryCatch(foo(2),error=function(e) ’’This is an error’’,
+ warning = function(e) ’’This is an warning’’)
[1] ’’This is an error’’
> tryCatch(foo(5),error=function(e) ’’This is an error’’,
+ warning = function(e) ’’This is an warning’’)
[1] ’’This is an warning’’
> tryCatch(foo(29),error=function(e) ’’This is an error’’,
+ warning = function(e) ’’This is an warning’’)
[1] 33
3 In some situation, however, this may not be desired. For example, a large simula-
tion is being run, and one run may fail, which nevertheless should not halt the entire
simulation.
56 3. R programming
4 In
this example there are 26 methods. Most of them can be seen by typing its name,
such as summary.data.frame. However, five of them are asterisked, indicating that can
not be viewed directly by typing their names. We can read these methods by, e.g.,
> getAnywhere(summary.loess)
A single object matching ‘summary.loess’ was found
It was found in the following places
registered S3 method for summary from namespace stats
namespace:stats
with value
function (object, ...)
{
class(object) <- ’’summary.loess’’
object
}
<environment: namespace:stats>
3. R programming 57
3.4 Exercises
1. Consider measurements of heights (in centimeters) of five persons at
ages 8 and 15, respectively. Let x1=c(75.1,108.9,105.3,83.9,101.2) and x2
= c(131.1,175.8,179.7,154.6,163.9). Now, we would like to know the change
of height per year for each of them. Mathematically, this is to calculate:
1
∆ = 15−8 (x2 − x1 ). Then, (a) define a function that returns the change
of height per year for each of them, and (b) define a function (i.e., binary
operator %∆%) that takes x2 and x1 as the two parameters and returns
the changes of height per year (∆) for the five persons.
2. Define a function, namely center, which is expected to return either
the mean, or median, or mode, depending on the expression to be evaluated.
The mean and median are given by the generic functions mean and median,
and the mode is given by a user-defined function mode. (We’ll explain the
mode function in Chapter 4).
mode <- function (x) {
y <- as.integer(names(sort(-table(x)))[1])
print(y)
}
Next, sample 20 numbers randomly with replacement from numbers 1,
2, 3, 4, and 5. Find the mean, median, and mode using the center function.
3. In mathematics, the Kronecker product, denoted by ⊗, is an operation
on two matrices of arbitrary size resulting in a block matrix. If A is an m×n
matrix and B is a p × q matrix, then the Kronecker product A ⊗ B is the
mp × nq block matrix
a11 B . . . a1n B
A⊗B =
.. .. ..
. . .
a B · · · amn B
m1
a11 . . . a1n
where A = ... ..
..
. .
am1 · · · amn
Then, (a) Define binary
operator (denoted by %@%) for the Kronecker
7 0 1.0 0.2
product; (b) calculate ⊗ .
0 5 0.2 1.0
5
4. In mathematics, the Fibonacci numbers are the following sequence of
numbers: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, . . . . . . Note that the first two
Fibonacci numbers are 0 and 1, and each remaining number is the sum of
the previous two:
0+1=1
1+1=2
5 The Fibonacci sequence is named after Leonardo of Pisa, who was known as Fi-
1+2=3
2+3=5
3+5=8
5 + 8 = 13
..
.
In mathematical terms, the sequence Fn of Fibonacci numbers is defined
by the recurrence relation
Fn = Fn−1 + Fn−2
with seed values
F0 = 0 and F1 = 1
Write a recursive R function that gives the Fibonacci numbers.
5. The Bayesian information criterion (BIC) or Schwarz Criterion is a cri-
terion for model selection among a class of parametric models with different
numbers of parameters.
The BIC is an asymptotic result derived under the assumptions that the
data distribution is in the exponential family. Let x = the observed data;
n = the number of data points in x (i.e., the number of observations); k =
the number of free parameters to be estimated (If the estimated model is
a linear regression, k is the number of regressors, including the constant);
p(x|k) = the likelihood of the observed data given the number of parame-
ters; L = the maximized value of the likelihood function for the estimated
model.
The formula for the BIC is:
BIC = −2 · ln L + k ln(n)
Under the assumption that the model errors or disturbances are normally
distributed, this becomes (up to an additive constant, which depends only
on n and not on the model):
BIC=nln RSS n + k ln(n)
where RSS is the residual sum of squares from the estimated model.
Write a function that gives BIC values of normal data with overall mean
µ and variance σ 2 .
6*. Lexical scope and exception handling: The following R codes are used
to mimic a bank account. A functioning bank account needs to have a bal-
ance or total, a function for making withdrawals, a function for making
deposits and a function for stating the current balance. This is achieved by
creating the three functions within account and then returning a list con-
taining them. When account is invoked it takes a numerical argument total
and returns a list containing the three functions. Because these functions
are defined in an environment which contains total, they will have access
to its value.
The special assignment operator, <<-, is used to change the value associ-
ated with total. This operator looks back in enclosing environments for an
environment that contains the variable total. When such an environment
is found, it replaces the value, in that environment, with the value of right
60 3. R programming