前言
Apply系列函数作为R语言中用于替换for和while循环的利器,在批量循环计算的过程中发挥着非常重要的作用,其他的R包如dplyr,plyr和data.table的很多数据操作思路和apply系列函数有很多的借鉴和相似之处,最经典的就是dplyr中的group_by+summarize可以完美的替代tapply函数。
当然在现阶段,国外推特有一个很火的选择题,就是“你在使用R语言的时候,是使用tidyverse还是base R”。人们都说tidyverse完全是开发了一套独立于R语言的另一套语法,几乎是在完全不使用base R的情况下完成Data science的所有流程。但是,对于一个真正的R爱好者来说,tidyverse固然好用,但是R基础语法必须还是要掌握,对于自己后期编写自己的R包或者集成函数都是极好的。
apply
Apply Functions Over Array Margins
Description:
Returns a vector or array or list of values obtained by applying a
function to margins of an array or matrix.
Usage:
apply(X, MARGIN, FUN, ...)
Arguments:
X: an array, including a matrix.
MARGIN: a vector giving the subscripts which the function will be
applied over. E.g., for a matrix ‘1’ indicates rows, ‘2’
indicates columns, ‘c(1, 2)’ indicates rows and columns.
Where ‘X’ has named dimnames, it can be a character vector
selecting dimension names.
FUN: the function to be applied: see ‘Details’. In the case of
functions like ‘+’, ‘%*%’, etc., the function name must be
backquoted or quoted.
...: optional arguments to ‘FUN’.
apply函数重要的参数有3个,传入的数据X,操作的行列Margin,运行的函数FUN。
传入的数据X:array或matrix,但是基于实际情况,传入的数据大部分都是矩阵
Margin:1代表处理行,2代表处理列
FUN:处理的函数,可以是自带函数或者匿名函数
a<-matrix(runif(100)*10,nrow=20)
apply(a, 1, mean)
apply(a, 1 , function(x){x[1]+x[2]})
apply(a, 1, mean, na.rm=TRUE)
sapply & lapply
apply的短板在于无法处理数据框或者list数据结构,常规情况下的数据都是由外部数据导入或者SQL数据库当中提取,所以对于dataframe的数据是很常见的。sapply和lapply其实就和表兄弟相似,两者工作的方法是一样的,只是根据参数的不同导致返回值的数据类型不同,sapply返回为vector,而lapply返回为list
Description:
‘lapply’ returns a list of the same length as ‘X’, each element of
which is the result of applying ‘FUN’ to the corresponding element
of ‘X’.
‘sapply’ is a user-friendly version and wrapper of ‘lapply’ by
default returning a vector, matrix or, if ‘simplify = "array"’, an
array if appropriate, by applying ‘simplify2array()’. ‘sapply(x,
f, simplify = FALSE, USE.NAMES = FALSE)’ is the same as ‘lapply(x,
f)’.
sapply(subset(iris, select=-Species), mean)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.199333
----------------------------------
lapply(subset(iris, select=-Species), mean)
$Sepal.Length
[1] 5.843333
$Sepal.Width
[1] 3.057333
$Petal.Length
[1] 3.758
$Petal.Width
[1] 1.199333
之于大家在使用的时候是sapply还是lapply,根据大家的实际情况和后续数据分析的需要来进行选择,但是无论选择哪一个,都比for循环快还节省内存。
tapply & sapply+split
tapply也同样是对数据进行批量操作,但是是根据分组情况进行的计算(也就是factor)
Description:
Apply a function to each cell of a ragged array, that is to each
(non-empty) group of values given by a unique combination of the
levels of certain factors.
Usage:
tapply(X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE)
INDEX便是分组变量名称,X是需要处理的数据列
tapply(iris$Petal.Length, iris$Species, sum)
setosa versicolor virginica
73.1 213.0 277.6
sapply+split是完全可以代替tapply。split就是将数据按照因子分组并返回为list,然后sapply处理。
sapply(split(iris$Petal.Length,iris$Species), mean)
setosa versicolor virginica
1.462 4.260 5.552
得到的结果和使用tapply是完全一样的
结语
apply家族函数还包含mapply和vapply等,基于大家使用R的经验可以自行查看文档去使用,上面介绍的便是常用的apply函数,可以极大程度的节省时间和减少for循环运行所消耗的时间和内存。
functional > purrr or apply series > for & while
上诉便是我本人在使用R语言处理更重数据时得出的结论,和大家分享