R语言教程-R编程3

函数部分

递归调用

在函数内调用自己叫做递归调用。 递归调用可以使得许多程序变得简单, 但是往往导致程序效率很低, 需谨慎使用。

R中在递归调用时, 最好用 Recall 代表调用自身, 这样保证函数即使被改名(在R中函数是一个对象, 改名后仍然有效)递归调用仍指向原来定义。

斐波那契数列

fib <- function(n){
if(n == 0) return(0)
else if(n == 1) return(1)
else if(n >= 2){
Recall(n-1) + Recall(n-2)
}
}
cat("n = 3", " x[n] =", fib(3), "\n")
for(i in c(3,5,8,9)) cat("i = ", i, " x[i] =", fib(i), "\n")

向量化
自定义的函数,如果其中的计算都是向量化的, 那么函数自动地可以接受向量作为输入,结果输出向量。

f <- function(x){
x^2
}
a <- c(2,3,4,5)
f(a)

分段函数
分段函数

# 一元函数版本,不能处理向量输入
g <- function(x){
if(abs(x) <= 1) return(x^2)
else return(1)
}
g(-2)
g(0.8)

改写1:

g1 <- function(x){
# 生成与x长度个的0向量,即先将输出的结果向量化
y <- numeric(length(x))
for(i in seq(along=x)){
if(abs(x[i]) <= 1) {
y[i] <- x[i]^2
} else {
y[i] <- 1
}
}

y
}
g1(c(0.8,2))

改写2:

gv <- function(x){
y <- numeric(length(x))
sele <- abs(x) <= 1
y[sele] <- x[sele]^2
y[!sele] <- 1.0

y
}
gv(c(0.8,2))

改写3:

g3 <- function(x){
ifelse(abs(x) <=1, x^2, 1)
}
g3(c(0.8,2))

函数Vectorize可以将g改写2那样的操作自动化。

g <- function(x){
if(abs(x) <= 1) {
return(x^2)
} else {
return(1)
}
}
# 如果直接使用该函数,该函数不能处理向量,只会显示向量中的第一个数的结果。
g(c(-2, -0.5, 0, 0.5, 1, 1.5))
# 使用vectorize()函数向量化
g4 <- Vectorize(g)
g4(c(-2, -0.5, 0, 0.5, 1, 1.5))

还可以使用purrr::map()或基本R的lapply()等泛函实现对各个元素的函数变换。后面将会涉及到。

无名函数
R允许使用没有函数名的函数对象, lapply类的函数经常使用无名的函数对象作为输入。

vapply的简单说明

# 第三个参数FUN.VALUE用以指明返回值的形式,可以看作返回值的模板(0.0)。
vapply(iris[,1:4], function(x) max(x) - min(x),0.0)

iris是R中的一个例子数据框,有150个观测, 前4个变量是数值型的, 最后一个变量Species是有三个水平的因子。 这个语句对前4列分别计算极差。
lapply这样的函数称为“泛函”。后面会有相关内容。