【上一篇:83.关于purrr包中的函数与apply函数的运行原理说明-十分详细】
【下一篇:85.关于tapply函数】
之所以上篇将apply写那么细,是因为我一直有无法理解和记忆apply()返回结果的困扰。好好研究一遍之后发现只要记住以下几个点其实就理解了。
1)apply()的输入是array或matrix,也可以是任何有dim信息的对象[也许不太对,大致是这样],输出是向量、数组或列表[想得到数据框?用类似as.data.frame)()函数转吧]。
2)apply()的输出格式由调用函数返回向量的长度和simplify参数共同确定。
3)apply()是for循环的紧凑版,理解其最终输出可以分两个阶段:第一阶段,每次调用函数的返回结果存储在list中,第二阶段,循环结束后再决定要不要尽可能简化输出,atomic vector的结构比list简单,所以list可以简化成atomic vector。
下面开始apply族的其他函数解读。
lapply函数
Apply a Function over a List or Vector。(这里的vector我很费解,难道是因为List也是vector?)
lapply()函数是参数最少,返回结果也很固定的一个函数。
lapply(X, FUN, ...)
输入参数
X:输入对象,一个List(必须),如果是其他对象,会用as.list()强制转换成list。例如如果是data.frame,就会先as.list(dataframe)。
FUN:调用的函数
...:传递到FUN的可选参数
输出结果
lapply()的输出也是列表,长度与输入X的长度一致。
# 创建一个list
> (x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE)))
$a
[1] 1 2 3 4 5 6 7 8 9 10
$beta
[1] 0.04978707 0.13533528 0.36787944 1.00000000 2.71828183
[6] 7.38905610 20.08553692
$logic
[1] TRUE FALSE FALSE TRUE
# 求列表中的每个元素求均值
> lapply(x, mean)
$a
[1] 5.5
$beta
[1] 4.535125
$logic
[1] 0.5
# 创建一个数据框
> (n<-data.frame(a=1:5,b=6:10))
a b
1 1 6
2 2 7
3 3 8
4 4 9
5 5 10
# 如果输入对象是数据框,则会先被as.list()强制转成list
> as.list(n)
$a
[1] 1 2 3 4 5
$b
[1] 6 7 8 9 10
sapply函数
sapply()函数是lapply()函数的用户优好版,输入参数一致,但输出更多样化,可以根据自己的需要设置。
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
输入参数
simplify:逻辑值或字符串,表示是否结果应该尽可能地被简化为向量、矩阵或更高维度的数组。默认为TRUE,表示合适的情况下简化为向量或矩阵;如果simpliy="array",表示结果可能是数组;当然不简化的时候输出和lapply()也一样是list啦。
sapply()函数中的简化是只有在每次调用FUN后的结果长度相同时发生的。每次调用FUN后返回的结果长度为1,则最终结果简化为向量;大于1,则最终结果简化为矩阵,矩阵的列数等于X的元素个数。
simplify="array"的时候,简化的发生是通过调用simplify2array()函数实现的。
如果进行了简化,则输出类型在将成对列表强制转换为列表之后,由层次结构中返回值的最高类型NULL < raw < logical < integer < double < complex < character < list < expression确定。
USE.NAMES:逻辑值,默认为TRUE,表示如果X是character且结果也没有names的话,就将X作为结果的names。[好吧,我测试了几种情况也不知道这个参数实在怎么应用的。总之,如果输入有names,那结果的名字就由输入的names确定了。]前面一直在举数字计算的例子,这里举一个输入是character类型的例子吧,也换换心情。
> v <- list(A=letters[1:4],B=letters[5:8])
# 默认简化
> sapply(v, paste, "-lucky")
A B
[1,] "a -lucky" "e -lucky"
[2,] "b -lucky" "f -lucky"
[3,] "c -lucky" "g -lucky"
[4,] "d -lucky" "h -lucky"
# 不简化
> sapply(v, paste, "-lucky", simplify = F)
$A
[1] "a -lucky" "b -lucky" "c -lucky" "d -lucky"
$B
[1] "e -lucky" "f -lucky" "g -lucky" "h -lucky"
sapply(x, f, simplify = FALSE, USE.NAMES = FALSE)与lapply(x,f)等价。
vapply函数
vapply()函数与sapply()函数相似,但是有一个预先指定的返回值类型,所以它可以更安全(有时更快)使用。
vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
FUN.VALUE:一个自己生成的向量,给定FUN返回值的模板,可以给返回值加上name,这样简化成matrix的时候就有行名了。
vapply()返回一个与FUN.VALUE类型匹配的vector或数组。如果length(FUN.VALUE) == 1,则返回与X长度相同的向量,否则返回一个数组。如果FUN.VALUE不是一个数组,结果是一个length(FUN.VALUE)行和length(X)列的矩阵,否则是一个 dim(a) == c(dim(FUN.VALUE), length(X))的数组。
# 这个例子来自lapply函数的说明文档
# 返回的i39是一个list
> i39 <- sapply(3:9, seq)
# 求i39中每个元素的fivenum,因为FUN返回向量长度相等,所以默认简化为matrix
> sapply(i39, fivenum)
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1.0 1.0 1 1.0 1.0 1.0 1
[2,] 1.5 1.5 2 2.0 2.5 2.5 3
[3,] 2.0 2.5 3 3.5 4.0 4.5 5
[4,] 2.5 3.5 4 5.0 5.5 6.5 7
[5,] 3.0 4.0 5 6.0 7.0 8.0 9
# 每次调用fivenum函数,返回的向量没有name,这里通过设定FUN.VALUE指定了格式,带名字的向量。
> vapply(i39, fivenum,
+ c(Min. = 0, "1st Qu." = 0, Median = 0, "3rd Qu." = 0, Max. = 0))
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
Min. 1.0 1.0 1 1.0 1.0 1.0 1
1st Qu. 1.5 1.5 2 2.0 2.5 2.5 3
Median 2.0 2.5 3 3.5 4.0 4.5 5
3rd Qu. 2.5 3.5 4 5.0 5.5 6.5 7
Max. 3.0 4.0 5 6.0 7.0 8.0 9
本篇实在写不下了,下篇再写tapply()。
【上一篇:83.关于purrr包中的函数与apply函数的运行原理说明-十分详细】
【下一篇:85.关于tapply函数】