R语言最优秀的是它的向量化编程,这其中apply族函数扮演了非常重要的角色。apply族函数是由apply、sapply、lapply、mapply、tapply等函数组成的。熟练使用apply族函数,能够简化程序,提高代码的运算速度。
apply是最基本的函数。为了方便演示,选取了R自带的数据框mtcars的前4行和前5列,并赋值给data。a1返回的结果是data数据每一行的和,由于每行都有一个和,所以a1是4个元素组成的数值向量。a2返回的结果是data数据每一列的均值,同样,a2是5个元素组成的数值向量。
# 获取内置数据
data <- mtcars[1:4,1:5]
print(data)
## mpg cyl disp hp drat
## Mazda RX4 21.0 6 160 110 3.90
## Mazda RX4 Wag 21.0 6 160 110 3.90
## Datsun 710 22.8 4 108 93 3.85
## Hornet 4 Drive 21.4 6 258 110 3.08
# 对数据框每行求和
a1 <- apply(data,1,sum)
print(a1)
## Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive
## 300.90 300.90 231.65 398.48
# 对数据框每列求均值
a2 <- apply(data,2,mean)
print(a2)
## mpg cyl disp hp drat
## 21.5500 5.5000 171.5000 105.7500 3.6825
apply函数的第一个参数表示数据,第二个参数表示维度(1表示行,2表示列),第三个参数表示在维度上操作的函数。需要注意的是第三个参数,用作演示的函数是R自带的函数(sum、mean),当然,这里也可以是自己定义的函数。
# 自定义函数(求极差)
func <- function(x){
result <- diff(range(x))
return(result)
}
# 对数据框每列求极差
a3 <- apply(data,2,func)
print(a3)
## mpg cyl disp hp drat
## 1.80 2.00 150.00 17.00 0.82
sapply的用法比apply要更灵活一些,同样,用data做演示。计算数据框data每列的数据范围,用sapply进行计算,返回的结果存储在s1里,sapply第一个参数是需要计算的数据框,第二个参数是函数,第三个参数simplify=T(默认)代表返回的结果简化表示,s1的数据格式为矩阵。
s1 <- sapply(data,range,simplify = T)
class(s1)
## [1] "matrix"
如果不想让计算的结果自动合并成矩阵,可以设置simplify=F,将返回一个列表,列表的每个组件包含了data数据框每列的range函数计算结果。
s2 <- sapply(data,range,simplify = F)
class(s2)
## [1] "list"
sapply一个更常见的用法是针对列表的组件进行操作。例如有n个数据框,对每个数据框都要进行相同的操作,常规方法用循环遍历,但操作体验差,速度慢,更优的解决方案是:先对单个数据框定义处理函数,然后用sapply对所有数据框采取相同操作。
# 定义一个数据框组成的list
df_list <- list(a=mtcars[1:3,1:4],
b=airquality[1:3,1:4],
c=iris[1:3,1:4])
# 自定义函数(求数据框欧氏距离的最大值)
max_func <- function(x){
d <- dist(x,p=2)
return(max(d))
}
# sapply对每个数据框计算
s3 <- sapply(df_list,max_func)
print(s3)
## a b c
## 54.7744466 72.3488770 0.5385165
lapply的用法与sapply基本相同,只不过返回的结果是以list储存的。
# 求每一列的均值
l1 <- lapply(data,mean)
print(l1)
## $mpg
## [1] 21.55
##
## $cyl
## [1] 5.5
##
## $disp
## [1] 171.5
##
## $hp
## [1] 105.75
##
## $drat
## [1] 3.6825
class(l1)
## [1] "list"
mapply在sapply和lapply的基础上进行了拓展,可以应用在多个变量上。a、b、c三个数值向量,第一次需要计算1*2*3
,第二次需要计算2*3*4
,…,以此类推。当需要每次变化的变量有多个时,用mapply计算更方便快捷。
a <- 1:5
b <- 2:6
c <- 3:7
m1 <- mapply(prod,a,b,c)
print(m1)
## [1] 6 24 60 120 210
tapply主要用在分组计算上。分组计算是常见的数据处理操作,能够处理分组计算的函数也不少,tapply的优势是简单便捷。
# 数据框
group_df <- data.frame(value=1:6,label=rep(c("a","b"),3,each=1))
print(group_df)
## value label
## 1 1 a
## 2 2 b
## 3 3 a
## 4 4 b
## 5 5 a
## 6 6 b
# 按照label分组计算value和
t1 <- tapply(X =group_df$value,INDEX = group_df$label,sum)
print(t1)
## a b
## 9 12