R Programming/Working with functions
Looking at the code of a function
edit- 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)
Creating your own function
editA simple function without argument which doesn't return anything
edit> fn <- function(){
+ print("hello")
+ }
> fn()
[1] "hello"
Returning an object
editBy 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 explicitly using return() (but as it is the last line, you could simply use x instead):
> test <- function() {
+ x <- 1
+ z <- 2
+ return(x)
+ }
> res <- test()
> res
[1] 1
- ) More precisely, it is not the "last line" but rather the value of the last evaluation which is returned from the function.
Adding arguments
editIt is possible to add arguments.
square <- function(x){
x2 <- x^2
return(x2)
}
square(x = 2)
Note that the above function would rather be written (and be more efficient) as
square <- function(x) x^2
(as the last value is returned)
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")
res
}
N <- 100
u <- rnorm(N)
x <- rnorm(N) + 1
y <- 1 + x + u
ols(y~x)
Recursive functions
editR supports recursive functions. The function below computes Fibonacci numbers recursively.
> fib <- function(n) {
if(n > 2) {
m <- fib(n-1)
c(m, sum(tail(m, 2)))
}
else rep(1, n)
}
> fib(30)
[1] 1 1 2 3 5 8 13 21 34 55
[11] 89 144 233 377 610 987 1597 2584 4181 6765
[21] 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040
Functions as Objects
editR 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
Higher-order functions
editYou can use higher-order functions in R. Contrary to common belief, using them instead of loops, is not faster, because the apply function has a for-loop inside its definition. Use them only to improve clarity of your code.[2]
apply
editapply 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
edittapply 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
editThis 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
References
edit- ↑ http://r.789695.n4.nabble.com/Optional-data-argument-for-a-function-tp850247p850247.html
- ↑ Patrick Burns, The R Inferno, p. 24