既含睇兮又宜笑,子慕予兮善窈窕。
—— 《山鬼》
apply()函数算是R语言里面很基础的一个函数,同时还有sapply()、lapply()、tapply()函数精简了apply()的用法。
apply()函数是一个很R语言的函数,可以起到很好的替代冗余的for循环的作用,R语言的循环操作for和while,都是基于R语言本身来实现的,而向量操作是基于底层的C语言函数实现的,所以使用apply()家族进行向量计算是高性价比的。apply()可以面向数据框、列表、向量等,同时任何函数都可以传递给apply()函数。
先简单的介绍一下rbind()和cbind()函数
rbind()#以行的形式
cbind()#以列的形式
> x > View(x)> class(x)[1] "matrix"
> y > View(y)
apply()函数的用法如下:
#apply:对每个小片断独立进行操作
#apply(X, MARGIN, FUN, ...)
#X:数组、矩阵、数据框;
#MARGIN: 按行计算或按按列计算,1表示按行,2表示按列
-MARGIN=1`: 操作基于行
-MARGIN=2`: 操作基于列
-MARGIN=c(1,2)`: 对行和列都进行操作
#FUN: 使用哪种操作,内置的函数有mean(平均值)、medium(中位数)、sum(求和)、min(最小值)、max(最大值),当然还包括广大的用户自定义函数
#按行循环,让数据框的x1列加1,并计算出x1,x2列的均值
示例一:
> x > 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> 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
也可以通过for循环来实现上述结果
> df> for(i in 1:nrow(x)){+ row+ df+ } > df V1 V21 4 3.52 4 3.03 4 2.54 4 2.05 4 2.56 4 3.07 4 3.58 4 4.0
也可以直接通过向量化来实现上述结果
> data.frame(x1=x[,1]+1,x2=rowMeans(x)) x1 x21 4 3.52 4 3.03 4 2.54 4 2.05 4 2.56 4 3.07 4 3.58 4 4.0
示例二:
使用apply()对一个matrix求和
> m1 > m1 [,1] [,2] [,3] [,4] [,5] [,6][1,] 1 6 1 6 1 6[2,] 2 7 2 7 2 7[3,] 3 8 3 8 3 8[4,] 4 9 4 9 4 9[5,] 5 10 5 10 5 10> a_m1 > a_m1[1] 15 40 15 40 15 40
lapply()函数的用法如下:
lapply()函数中多出来的l代表的是list,所以lapply()和apply()的区别在于输出的格式,lapply()的输出是一个列表(list),所以 lapply()函数不需要MARGIN参数.
lapply()用来对list、data.frame数据集进行循环,返回和X长度同样的list结构作为结果集
lapply可以很方便地把list数据集进行循环操作,还可以用data.frame数据集按列进行循环,但如果传入的数据集是一个向量或矩阵对象,那么lapply会分别循环矩阵中的每个值,而不是按行或按列进行分组计算
示例一:
lapply对矩阵进行循环
> x > x x1 x2[1,] 3 2[2,] 3 1[3,] 3 4[4,] 3 5> class(x)[1] "matrix"> lapply(x, sum)[[1]][1] 3[[2]][1] 3[[3]][1] 3[[4]][1] 3[[5]][1] 2[[6]][1] 1[[7]][1] 4[[8]][1] 5
示例二:
lapply对数据框进行循环
> x x1 x2[1,] 3 2[2,] 3 1[3,] 3 4[4,] 3 5> lapply(data.frame(x), sum)$x1[1] 12$x2[1] 12
示例三:
lapply对向量进行循环
> movies > class(movies)[1] "character"> movies_lower > movies_lower[[1]][1] "spyderman"[[2]][1] "batman"[[3]][1] "vertigo"[[4]][1] "chinatown"> str(movies_lower)List of 4 $ : chr "spyderman" $ : chr "batman" $ : chr "vertigo" $ : chr "chinatown"
我们可以看到,输出的内容是以list形式给出的,为了方便,我们可以使用unlist()函数进行整合
> movies_lower > str(movies_lower) chr [1:4] "spyderman" "batman" "vertigo" "chinatown"> movies_lower[1] "spyderman" "batman" "vertigo" "chinatown"
sapply()函数的用法如下:
sapply()函数做的事情和lapply()一样,可以理解为是一个简化的lapply,返回的是一个向量(vector)使得对解读更加友好,其使用方法和lapply一样,sapply增加了2个参数simplify和USE.NAMES,主要就是让输出看起来更友好,返回值为向量,而不是list对象。simplify = T可以将输出结果数组化,如果设置为false,sapply()函数就和lapply()函数没有差别了,use.NAMEs = T可以设置字符串为字符名。
#sapply(X, FUN, ..., simplify=TRUE, USE.NAMES = TRUE)
#simplify: 是否数组化,当值array时,输出结果按数组进行分组
#USE.NAMES: 如果X为字符串,TRUE设置字符串为数据名,FALSE不设置
> x > x x1 x2[1,] 3 2[2,] 3 1[3,] 3 4[4,] 3 5#对矩阵计算,计算过程同lapply函数,但是lapply返回值为list,sapply是向量> sapply(x, sum)[1] 3 3 3 3 2 1 4 5#对数据框计算> sapply(data.frame(x), sum)x1 x2 12 12 > class(lapply(x, sum))[1] "list"> class(sapply(x, sum))[1] "numeric"#如果simplify=FALSE和USE.NAMES=FALSE,那么完全sapply函数就等于lapply函数了> lapply(data.frame(x), sum)$x1[1] 12$x2[1] 12> sapply(data.frame(x), sum, simplify=FALSE, USE.NAMES=FALSE)$x1[1] 12$x2[1] 12
#对于simplify为array时,我们可以参考下面的例子,构建一个三维数组,其中二个维度为方阵> a> a[1] 1 2#按数组分组> sapply(a,function(x) matrix(x,2,2), simplify='array'), , 1 [,1] [,2][1,] 1 1[2,] 1 1, , 2 [,1] [,2][1,] 2 2[2,] 2 2#默认情况,则自动合并分组> sapply(a,function(x) matrix(x,2,2)) [,1] [,2][1,] 1 2[2,] 1 2[3,] 1 2[4,] 1 2> val> val[1] "a" "b" "c" "d" "e" "f"#默认设置数据名> sapply(val,paste,USE.NAMES=TRUE) a b c d e f "a" "b" "c" "d" "e" "f" # USE.NAMES=FALSE,则不设置数据名> sapply(val,paste,USE.NAMES=FALSE)[1] "a" "b" "c" "d" "e" "f"
****总结
tapply()函数的用法如下:
#tapply用于分组的循环计算,通过INDEX参数可以把数据集X进行分组,相当于group by的操作
#tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
Arguments:
-X: 一个对象,一般都是向量
-INDEX: 一个包含分类因子的列表(list)
-FUN: 对X里面每个元素进行操作的函数
#simplify : 是否数组化,当值array时,输出结果按数组进行分组
#比如,计算不同品种的鸢尾花的花瓣(iris)长度的均值
#通过iris$Species品种进行分组
> data(iris)> head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species1 5.1 3.5 1.4 0.2 setosa2 4.9 3.0 1.4 0.2 setosa3 4.7 3.2 1.3 0.2 setosa4 4.6 3.1 1.5 0.2 setosa5 5.0 3.6 1.4 0.2 setosa6 5.4 3.9 1.7 0.4 setosa> tapply(iris$Sepal.Width, iris$Species, median) setosa versicolor virginica 3.4 2.8 3.0
也可以直接通过group by来实现上述结果
> iris %>% group_by(Species) %>%+ summarise(mean(Sepal.Width))# A tibble: 3 x 2 Species `mean(Sepal.Width)` 1 setosa 3.432 versicolor 2.773 virginica 2.97



