9.3 apply系列函数

在 base R 中,apply系列函数是比较著名的一组函数,虽然dplyrpurrr包的功能可以取代。但是我们作为学习者,还是需要了解 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,或者是自定义的函数。

…: 函数中其它参数的设置,如有需要的话。

我们首先看一个简单的示例:

x <- list(vec = c(1,3,5,NA), int = 1:10, logic = c(TRUE,FALSE,FALSE,TRUE))
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

  • 长度
x <- list( a = c(1.0,2.0,3.0),b = c(1,3,3),d = c(8,10,3))
y <- list( a = c(1:3),b = c(1,3,4),d = c(8,10,3))

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。

  • 类型
x <- list(vec = c(1,3,5,NA), int = 1:10, logic = c(TRUE,FALSE,FALSE,TRUE))
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)代表行列。

x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
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

对于大部分商业数据分析师而言,较少遇到多维数据集