R Programming/Working with functions

Looking at the code of a function

  • You can type the name of the function in the console without any round brackets after the name. This will print the code of the function in the console.
  • You can also use the page() function which opens a new editor window and prints the code of the function in this editor.
  • You can also use the trCopy() function in the TinnR package to copy the code of the function. Then you just have to paste it in a text editor to have a look at it.

Here is an example with the lm() function.

> lm
> page(lm)
> library(TinnR)
> trCopy(lm)
↑Jump back a section

Creating your own function

A simple function without argument which doesn't return anything

> fn <- function(){
+ print("hello")
+ }
> fn()
[1] "hello"


Returning an object

By default the value of the last line is returned. In the following example, we have a simple function with two objects. The last one is returned.

> test <- function(){
+ x <-1
+ z <- 2
+ }
> res <- test()
> res
[1] 2

The function can return an object using return().

> test <- function(){
+ x <-1
+ z <- 2
+ return(x)
+ }
> res <- test()
> res
[1] 1

Adding arguments

It is possible to add arguments.

square <- function(x){
        x2 <- x^2
        return(x2)
        }
square(x = 2)

The ... argument means that you can add other arguments which will be passed to functions inside the function.

plot2 <- function(x,...){
        plot(x, type = "l", ...)
        }
plot2(runif(100), main = "line plot", col = "red")

It is possible to add a dataframe as argument[1]. Here is an example :

redplot <- function(z, y, data, env=parent.frame()) {
       if(!missing(data)){
                        z <- data[,deparse(substitute(z))]
                        y <- data[,deparse(substitute(y))]
                        }
        plot(z,y, col = "red", pch = 15)
} 
 
mydat <- data.frame(vm = rnorm(10),output = rnorm(10))
redplot(vm,output,data=mydat)

For estimation commands it is possible to add formulas as arguments. For instance, we can create our own function for ordinary least square using a formula interface.

ols <- function(formula, data = list()){
        mf <- model.frame(formula=formula, data=data)
        X <- model.matrix(attr(mf, "terms"), data=mf)
        y <- model.response(mf)
        beta <- solve(t(X)%*%X)%*%t(X)%*%y
        se <- sqrt( 1/(nrow(X) - ncol(X)) * sum((y - X%*%beta)^2) * diag(solve(t(X)%*%X)))
        res <- cbind(beta,se)
        colnames(res)<- c("Coefficients","Standard errors")
        return(res)
        }
N <- 100
u <- rnorm(N)
x <- rnorm(N) + 1
y <- 1 + x + u
ols(y~x)
↑Jump back a section

Recursive functions

R supports recursive functions. The function below computes Fibonacci numbers recursively.

> fib <- function(n) if (n>2) c(fib(n-1),sum(tail(fib(n-1),2))) else if (n>=0) rep(1,n)
> fib(10)
 [1]  1  1  2  3  5  8 13 21 34 55
↑Jump back a section

Functions as Objects

R functions can be treated as objects

> a =function(n) function(a) runif(a)
> b = a(1)
> b(10)
 [1] 0.8726873 0.9512367 0.5971435 0.5540743 0.6378967 0.4030071 0.2750673 0.1777123 0.6960378 0.3969920

This can be useful when wanting to make many different kinds of functions

> a = list()
> b = function(i){ i; function() runif(i)}
> for (i in 1:10) a[[i]] = b(i)
> a[[1]]()
[1] 0.2617396
> a[[2]]()
[1] 0.8822248 0.3374574
> a[[3]]()
[1] 0.0348156 0.4212788 0.6107646
↑Jump back a section

Higher-order functions

You can use higher-order functions in R. It is generally a good idea to use them rather than loops because R is optimized for them and can often run them faster than the equivalent loop.

apply

apply is the most basic of R's map functions. lapply, sapply and mapply are convenient interfaces for apply that work on lists, vectors and multiple vectors respectively

apply takes as arguments an array, a vector of the dimension to map along and a function. The following example is based on the apply documentation. It uses apply to compute column and row sums of a matrix.

x <- matrix(round(rnorm(100)),10,10)
col.sums <- apply(x, 2, sum)
row.sums <- apply(x, 1, sum)


tapply

tapply is similar to apply, but applies a function to each cell of a ragged array, that is to each (non-empty) group of values given by a unique combination of the levels of certain factors.

> x1 <- rnorm(10)
> x2 <- sample(1:2, 10, replace = T)
> cbind(x1,x2)
              x1 x2
 [1,] -1.7905021  1
 [2,]  1.2908169  2
 [3,] -2.1902513  2
 [4,]  0.4845488  1
 [5,]  0.2281593  1
 [6,]  0.2201302  1
 [7,]  2.1574243  1
 [8,]  0.5789705  2
 [9,]  1.3315188  1
[10,] -1.0029822  2
> tapply(x1, x2, sum)
        1         2 
 2.631279 -1.323446

Reduce

This function from the Reduce documentation cumulatively adds

> cadd <- function(x) Reduce("+", x, accumulate = TRUE)
> cadd(1:10)
 [1]  1  3  6 10 15 21 28 36 45 55
↑Jump back a section
Last modified on 23 September 2012, at 20:28