9.3 apply系列函数
在 base R 中,apply系列函数是比较著名的一组函数,虽然dplyr
和purrr
包的功能可以取代。但是我们作为学习者,还是需要了解 base R 里面的原生用法。apply系列函数包含了8个以apply结尾的函数,分别是:apply,eapply,lappy,mapply,rapply,sapply,tapply,vapply。他们都是对 R 的对象执行一个或某个功能函数,然后返回不行形式的数据格式。听起来就有“循环”的味道,事实上大部分的 apply 系列函数都可以用for
循环来实现,不过apply系列函数实现更加简洁高效。
相比起来,我不太喜欢 base R apply 系列函数的用法,喜欢更加优雅简洁的purrr
的循环迭代方式,所以该部分大家可以跳过或做简单了解即可。
apply系列函数简洁高效的原因是因为 R 语言里面的向量化,具体可以参考《R语言编程艺术》。
9.3.1 lapply 循环迭代
lapply 是 list 和 apply 的结合,lapply是对向量或列表数据应有一个功能函数,返回的数据结构是和前面的数据长度相等的列表。函数的参数如下:
lapply(X, FUN, ...)
其参数说明如下:
X: 一个向量或列表,或者是“expression” ,同样是列表。关于“expression” 可以查看帮助?expression
。
FUN:需要运行的函数,可以是任意函数,无论是base R ,R packages,或者是自定义的函数。
…: 函数中其它参数的设置,如有需要的话。
我们首先看一个简单的示例:
<- list(vec = c(1,3,5,NA), int = 1:10, logic = c(TRUE,FALSE,FALSE,TRUE))
x lapply(x, mean)
#> $vec
#> [1] NA
#>
#> $int
#> [1] 5.5
#>
#> $logic
#> [1] 0.5
添加 … 参数 ,给 mean 函数添加参数 na.rm=TRUE
lapply(x, mean,na.rm=TRUE)
#> $vec
#> [1] 3
#>
#> $int
#> [1] 5.5
#>
#> $logic
#> [1] 0.5
lapply 函数调用均值函数 mean 分别计算 vec,int,logic 三个向量的平均值,最后返回一个长度为3的列表。另外在 … 参数位置上我们添加了 na.rm =TRUE 参数,使mean 函数能忽略 NA 值。
lapply 的功能强大,并且应用场景多,在我们要使用“循环”时,多考虑能否通过 apply 函数实现。如前文所见,我们可以使用 apply 批量读取文件。
lapply 是 apply 系列函数中我唯一一个可能使用的
9.3.2 sapply
sapply 是lapply的简化版。函数的参数如下:
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
和 lapply 函数的参数差异,simplify 默认为TRUE,是否返回向量,矩阵,数组,如果情况允许。我们用lapply 的例子查看 sapply 的功能。
sapply(x ,mean)
#> vec int logic
#> NA 5.5 0.5
sapply(x ,mean,na.rm=TRUE)
#> vec int logic
#> 3.0 5.5 0.5
9.3.3 vapply 迭代安全函数
vapply 函数通过FUN.VALUE 参数确保返回值长度以及类型一致,详见?vapply
。
- 长度
<- list( a = c(1.0,2.0,3.0),b = c(1,3,3),d = c(8,10,3))
x <- list( a = c(1:3),b = c(1,3,4),d = c(8,10,3))
y
sapply(x,function(x) x[x==3])
#> $a
#> [1] 3
#>
#> $b
#> [1] 3 3
#>
#> $d
#> [1] 3
vapply(x,function(x) x[x==3],FUN.VALUE = 1.0)
#> Error in vapply(x, function(x) x[x == 3], FUN.VALUE = 1) :
#> 值的长度必需为1,
#> 但FUN(X[[2]])结果的长度却是2
# 同上
# vapply(x,function(x) x[x==3],FUN.VALUE = as.numeric(1))
vapply(y,function(x) x[x==3],FUN.VALUE = as.numeric(1))
相同的列表,相同的函数,使用 sapply 会返回信息不会报错,但是使用 vapply 会报错,因为b中有2个3,而a,d中只有1个3。
- 类型
<- list(vec = c(1,3,5,NA), int = 1:10, logic = c(TRUE,FALSE,FALSE,TRUE))
x vapply(x,mean,FUN.VALUE = 1L)
#> Error in vapply(x, mean, FUN.VALUE = 1L) : 值的种类必需是'integer',
#> 但FUN(X[[1]])结果的种类却是'double'
vapply 函数的 FUN.VALUE 参数必须设置,可以通过 as.integer/character等函数进行设置
9.3.4 apply 多维数据
apply 专门用来处理矩阵和数组数据。参数如下:
apply(X, MARGIN, FUN, ..., simplify = TRUE)
其中 MARGIN 参数,1代表行,2代表列,c(1,2)
代表行列。
<- cbind(x1 = 3, x2 = c(4:1, 2:5))
x class(x)
#> [1] "matrix" "array"
apply(x,MARGIN = 1,FUN = mean)
#> [1] 3.5 3.0 2.5 2.0 2.5 3.0 3.5 4.0
apply(x,MARGIN = 2,FUN = mean)
#> x1 x2
#> 3 3
apply(x,MARGIN = c(1,2),FUN = mean)
#> 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
对于大部分商业数据分析师而言,较少遇到多维数据集