84.关于apply族的lapply/sapply/vapply

2021-11-04  本文已影响0人  心惊梦醒

【上一篇: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函数】

上一篇下一篇

猜你喜欢

热点阅读