本节提要:
apply()
函数sapply()
函数lapply()
函数tapply()
函数
熟悉R编程的人都知道R语言的apply
家族,而R语言入门容易,简单学一学就能写出一些代码,而良好的编程习惯和优雅的代码风格却是一个长期潜移默化、逐步积累的过程。
R语言的apply
家族正是为你高效编程提供了可能性,其令人惊讶的处理方式可能会成为你选择它们的理由。
apply()
要点:
- 作用对象:数据框(dataframe)或 矩阵(matrix);
- 输出:一个向量;
- 关键参数:
MARGIN
与FUN
。
apply()
函数能够快速帮助你对数据框或矩阵按行(MARGIN = 1
)或列(MARGIN = 2
)的方式来进行处理,而这个处理正是由FUN
所定义的。
示例:
#a matrix
mtx <- matrix(1:9, byrow = T, nrow = 3)
mtx
# [,1] [,2] [,3]
#[1,] 1 2 3
#[2,] 4 5 6
#[3,] 7 8 9
apply(X = mtx,
MARGIN = 1, #by row
FUN = mean) #cal mean value (mean function)
#[1] 2 5 8
这段代码实现了对该矩阵按行取均值的操作,最后返回一个向量,分别对应每一行的均值,当然你也可以自定义函数,例如还是上面的目的,用自己写的函数来实现(当然这完全没必要):
apply(X = mtx,
MARGIN = 1, #by row
FUN = function(x){
sum(x)/length(x)
}) #cal mean value (custome function)
想给大家分享的是,这段代码里面的x
到底是个什么?答案是 向量。也就是说 apply()
函数讲数据框或矩阵给你拆成了一个个向量供你进行操作,我们来简单验证一下:
apply(X = mtx,
MARGIN = 1, #by row
FUN = function(x){
is.vector(x)
})
#[1] TRUE TRUE TRUE
sapply()
要点:
- 作用对象:数据框(dataframe),向量(vector)或 列表(list);
- 输出:向量(vector)或 矩阵(matrix);
- 关键参数:
FUN
。
从本质上看,R语言的数据框是一种特殊的列表(每个组件长度都相等的列表)。这个组件就是数据框的每一列,由于数据框的特点,这些组件的类型是不一样的,有的是字符型向量,有的是数值型向量等等。
首先来看sapply()
函数是如何处理列表的:
#a list
list <- list(a = sample(1:10, 5),
b = 1:5)
list
#$a
#[1] 4 6 8 1 5
#$b
#[1] 1 2 3 4 5
sapply(list, FUN = sum)
# a b
#24 15
最终是对列表的每个组件进行了函数(sum()
)的操作,返回了一个向量。
基于前面对数据框和列表之间联系的认识,我们很自然的就可以知道,如果将sapply()
函数作用到数据框上会发生什么:对数据框的每一列进行相应的操作:
#a dataframe
dataframe <- data.frame(a = sample(1:10, 5),
b = 1:5)
dataframe
# a b
#1 2 1
#2 9 2
#3 10 3
#4 5 4
#5 6 5
sapply(dataframe, FUN = sum)
# a b
#32 15
果然是对数据框的每一列进行了求和。
lapply()
要点:
- 作用对象:数据框(dataframe),向量(vector)或 列表(list);
- 输出:列表(list);
- 关键参数:
FUN
。
lapply()
和sapply()
函数很像,不同点在于前者的输出是列表,这在很多时候会给我们带来一些意想不到的便利。暂时只做一个简单的使用示例:
list <- list(a = sample(1:10, 5),
b = 1:5)
list
lapply(list, FUN = sum)
#$a
#[1] 38
#$b
#[1] 15
tapply()
要点:
- 作用对象:向量(vector);
- 输出:向量(vector);
- 关键参数:
INDEX
,FUN
。
tapply()
函数在进行分组统计时具有非常大的作用,简单理解来说,tapply()
函数就是对向量X按照因子INDEX
进行函数FUN
的操作。这里我们以鸢尾花内置数据集为例来看看:
head(iris)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1 5.1 3.5 1.4 0.2 setosa
#2 4.9 3.0 1.4 0.2 setosa
#3 4.7 3.2 1.3 0.2 setosa
#4 4.6 3.1 1.5 0.2 setosa
#5 5.0 3.6 1.4 0.2 setosa
#6 5.4 3.9 1.7 0.4 setosa
#calculate mean Sepal length for each species
tapply(iris$Sepal.Length,
INDEX = factor(iris$Species), #group by species
FUN = mean) #calculate mean value
# setosa versicolor virginica
# 5.006 5.936 6.588
这实际上和dplyr
的group_by()
很像,也就是说这个功能还可以用这段代码实现:
library(dplyr)
iris %>%
group_by(Species) %>%
summarise(mean = mean(Sepal.Length))
不过返回的是数据框罢了。