刚开始接触R语言时,会听到各种的R语言使用技巧,其中最重要的一条就是不要用循环,效率特别低,要用向量计算代替循环计算。
那么,这是为什么呢?原因在于R的循环操作for和while,都是基于R语言本身来实现的,而向量操作是基于底层的C语言函数实现的,从性能上来看,就会有比较明显的差距了。那么如何使用C的函数来实现向量计算呢,就是要用到apply的家族函数,包括apply, sapply, tapply, mapply, lapply, rapply, vapply, eapply等。
1. apply的家族函数
apply函数族是R语言中数据处理的一组核心函数,通过使用apply函数,我们可以实现对数据的循环、分组、过滤、类型控制等操作。但是,由于在R语言中apply函数与其他语言循环体的处理思路是完全不一样的,所以apply函数族一直是使用者玩不转一类核心函数。
apply函数本身就是解决数据循环处理的问题,为了面向不同的数据类型,不同的返回值,apply函数组成了一个函数族,包括了8个功能类似的函数。这其中有些函数很相似,有些也不是太一样的。
我一般最常用的函数为apply和sapply,下面将分别介绍这8个函数的定义和使用方法。
2. apply函数
apply函数是最常用的代替for循环的函数。apply函数可以对矩阵、数据框、数组(二维、多维),按行或列进行循环计算,对子元素进行迭代,并把子元素以参数传递的形式给自定义的FUN函数中,并以返回计算结果。
函数定义:
apply(X, MARGIN, FUN, ...)
参数列表:
X:数组、矩阵、数据框
MARGIN: 按行计算或按按列计算,1表示按行,2表示按列
FUN: 自定义的调用函数
…: 更多参数,可选
比如,对一个矩阵的每一行求和,下面就要用到apply做循环了。
> x<-matrix(1:12,ncol=3)
> apply(x,1,sum)
[1] 15 18 21 24
下面计算一个稍微复杂点的例子,按行循环,让数据框的x1列加1,并计算出x1,x2列的均值。
生成data.frame
> x <- cbind(x1 = 3, x2 = c(4:1, 2:5)); x
x1 x2
[1,] 3 4
[2,] 3 3
[3,] 3 2
[4,] 3 1
[5,] 3 2
[6,] 3 3
[7,] 3 4
[8,] 3 5
#> 自定义函数myFUN,第一个参数x为数据
#> 第二、三个参数为自定义参数,可以通过apply的'...'进行传入。
> myFUN<- function(x, c1, c2) {
c(sum(x[c1],1), mean(x[c2])) }
#>把数据框按行做循环,每行分别传递给myFUN函数,设置c1,c2对应myFUN的第二、三个参数
> apply(x,1,myFUN,c1='x1',c2=c('x1','x2'))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 4.0 4 4.0 4 4.0 4 4.0 4
[2,] 3.5 3 2.5 2 2.5 3 3.5 4
通过这个上面的自定义函数myFUN就实现了,一个常用的循环计算。
如果直接用for循环来实现,那么代码如下:
# 定义一个结果的数据框
> df<-data.frame()
# 定义for循环
> for(i in 1:nrow(x)){
row<-x[i,] # 每行的值
> df<-rbind(df,rbind(c(sum(row[1],1), mean(row)))) # 计算,并赋值到结果数据框
> }
# 打印结果数据框
> df