这一节主要将lapply
和sapply
两个函数,属于*apply
函数族的成员。
结论:lapply
和sapply
两个函数完成的功能相似,sapply
多数情况下,返回的结果要比lapply
更具有可读性,最差的情况是和lapply
返回的结果一样。所以尽量使用sapply
函数。
这函数的作用如下:
ach of the *apply functions will SPLIT up some data into smaller pieces, APPLY a function to each piece, then COMBINE the results. A more detailed discussion of this strategy is found in Hadley Wickham's Journal of Statistical Software paper titled 'The Split-Apply-Combine Strategy for Data Analysis'.
如果直接看上面这段话,可能还不太理解他的作用,看几个例子就能明白了
swirl作者采用的数据来自这里,该数据是一个194x30的data.frame,可以通过
> head(flags)
name landmass zone area population language religion bars stripes colours red green blue gold white black orange mainhue
1 Afghanistan 5 1 648 16 10 2 0 3 5 1 1 0 1 1 1 0 green
2 Albania 3 1 29 3 6 6 0 0 3 1 0 0 1 0 1 0 red
3 Algeria 4 1 2388 20 8 2 2 0 3 1 1 0 0 1 0 0 green
4 American-Samoa 6 3 0 0 1 1 0 0 5 1 0 1 1 1 0 1 blue
5 Andorra 3 1 0 0 6 0 3 0 3 1 0 1 1 0 0 0 gold
6 Angola 4 2 1247 7 10 5 0 2 3 1 0 0 1 0 1 0 red
circles crosses saltires quarters sunstars crescent triangle icon animate text topleft botright
1 0 0 0 0 1 0 0 1 0 0 black green
2 0 0 0 0 1 0 0 0 1 0 red red
3 0 0 0 0 1 1 0 0 0 0 green white
4 0 0 0 0 0 0 1 1 1 0 blue red
5 0 0 0 0 0 0 0 0 0 0 blue red
6 0 0 0 0 1 0 0 1 0 0 red black
跟python的panda库里的head
函数功能很相似。
接下来如果我们想知道每一列的数据的类型,该如何操作呢?如果自己写循环,应该比较累赘,这里lapply
和sapply
两个函数可以完成这件事情
cls_list <- lapply(flags, class)
> cls_list
$name
[1] "factor"
$landmass
[1] "integer"
...
$topleft
[1] "factor"
$botright
[1] "factor"
class
是我们想操作的function,如果想求均值,就改成mean
,flags
是数据,lapply
返回的结果是一个list,由于结果太长,我用省略号省略了。
那我们在看看用sapply
函数是什么效果
> sapply(flags, class)
name landmass zone area population language religion bars stripes colours red green
"factor" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer"
blue gold white black orange mainhue circles crosses saltires quarters sunstars crescent
"integer" "integer" "integer" "integer" "integer" "factor" "integer" "integer" "integer" "integer" "integer" "integer"
triangle icon animate text topleft botright
"integer" "integer" "integer" "integer" "factor" "factor"
同样的结果,但是形式上好看多了,可读性更强了,之前是一列内容,得往下翻好久。
接下来再举一些例子来对比这两个函数:
> flag_colors <- flags[, 11:17]
> head(flag_colors)
red green blue gold white black orange
1 1 1 0 1 1 1 0
2 1 0 0 1 0 1 0
3 1 1 0 0 1 0 0
4 1 0 1 1 1 0 1
5 1 0 1 1 0 0 0
6 1 0 0 1 0 1 0
> lapply(flag_colors, sum)
$red
[1] 153
$green
[1] 91
$blue
[1] 99
$gold
[1] 91
$white
[1] 146
$black
[1] 52
$orange
[1] 26
> sapply(flag_colors, sum)
red green blue gold white black orange
153 91 99 91 146 52 26
> flag_shapes <- flags[, 19:23]
> lapply(flag_shapes, range)
$circles
[1] 0 4
$crosses
[1] 0 2
$saltires
[1] 0 1
$quarters
[1] 0 4
$sunstars
[1] 0 50
> sapply(flag_shapes, range) # 返回的是一个matrix类型
circles crosses saltires quarters sunstars
[1,] 0 0 0 0 0
[2,] 4 2 1 4 50
按照课上的话来翻译说,sapply
就是简化lapply
的结果,但是有时候会遇到无法简化的情况,此时二者返回的结果一致。
书上举的例子,输出的篇幅较长,这里我仅仅提一下,以供自己回忆。
当lapply
返回的结果,每一维的维度不一致时,比如$circles
维度下有2个元素,$crosses
有五个元素,这时候就没法像之前的这样,组成矩阵或者向量的形式了,因为维度不一致。
所以结论就是:使用sapply
,不使用lapply
。