R语言apply系列函数的基本作用是对数组(array,可以是多维)或者列表(list)按照元素或元素构成的子集合进行迭代,并将当前元素或子集合作为参数调用某个指定函数。vector是一维的array,dataframe可以看作特殊的list。
作用目标 |
在每个元素上应用 |
在子集合上应用 |
array |
apply |
tapply |
list |
lapply (...) |
by |
其中 lapply(...) 为一族函数,包括简化版: sapply,递归版: rapply。其中sapply又可分为可设置返回值模板vapply和多变量版mapply。另外vector比较特殊,vector是一维的array,但是却不全是和array使用相同的函数。在按元素迭代的情况下,使用和list一样的 lapply 函数;而在按子集合迭代的情况下, tapply 和 by 都能用,只是返回值形式不同。
1. apply函数
在array上,沿margin方向,依次调用 FUN,返回结果通常为Array类型,如果返回值的向量长度不等,则返回List对象。margin表示数组引用的第几维下标(即array[index1, index2, ...]中的第几个index),margin = 1表示行,2表示列,c(1,2) 表示行和列。
– 举例1:
# 二维矩阵对象
x <- cbind(x1 = 3, x2 = c(4:1, 2:5))
dimnames(x)[[1]] <- letters[1:8]
apply(x, 2, mean, trim = .2)
apply(x, 1, mean, trim = .2)
apply(x, 2, sort)
– 举例2:
#三维数组对象,数据向量中的值被赋给数组中的值时,将遵循“主列顺序”,即第一个下标变化最快,最后的下表变化最慢。
z <- array(1:24, dim = 2:4)
apply(z, 3, mean)
apply(z, 1:2, function(x) seq_len(max(x)))
apply(z, 3, function(x) seq_len(max(x)))
注: 虽然vector是一维的array,但是不能使用apply,array只能用在二维及以上的array上,因为apply要求dim(X)的值必需是正数,vector对象的dim值为NULL。
2. tapply函数
按 indices 中的值分组,把相同值对应下标的array中的元素形成一个集合,应用到 FUN 。类似于group by indices的操作。当simplify = TRUE(默认)时,如果 FUN 返回的是一个值, tapply 返回Array,空值用NULL表示;若 FUN 返回多个值, tapply 返回list,空值使用NA表示。当simplify = FALSE时,tapply 都返回list 对象。 Array或list的长度和 indices 中不同值的个数相等。
当 FUN 为 NULL 的时候,返回一个长度和array中元素个数相等的vector,指示分组的结果,vector中相等的元素所对应的下标属于同一组。例如,返回c(1, 2, 1, 3, 2), 表示根据传入的 indices ,第1、3个元素作为一组,第2、5个元素作为一组,第4个元素作为一组。
– 举例1:
#tapply应用于vector
height <- c(174, 165, 180, 171, 160)
sex<-c("F","F","M","F","M")
#返回vector
tapply(height, sex, mean)
#返回list
tapply(height, sex, mean, simplify = F)
#因为函数fivenum返回多值,即使simplify = TRUE,也是返回list对象
tapply(height, sex, fivenum)
– 举例2:
#tapply应用于matrix
m <- matrix(c(1:10), nrow=2)
ind <- matrix(c(rep(1,5),rep(2,5)), nrow=2)
tapply(height, sex)
tapply(m, ind, mean)
tapply(m, ind, fivenum)
– 举例3:
#tapply实现crosstable功能
df<-data.frame(year=kronecker(2001:2003,rep(1,4)),loc=c('beijing','beijing','shanghai','shanghai'), type=rep(c('A','B'),6), sale=rep(1:12))
#以年份为行、地区为列计算销售总量
tapply(df$sale, df[,c('year','loc')], sum)
#以年份为行,类别为列计算销售总量
tapply(df$sale, df[,c('year','type')], sum)
#以年份,地区和类别计算销售总量
tapply(df$sale, df[,c('year','loc','type')],sum)
3. lapply函数
在 list 上逐个元素调用 FUN 。可以用于dataframe上,因为dataframe是一种特殊形式的list。若对象不是list和表达式类型,会先强制转换为list后再应用于FUN函数。
– 举例1:
#lapply应用于matrix
lst <- list(a=c(1:5), b=c(6:10))
lapply(lst, mean)
– 举例2:
# 非List会先强制转换为List后再求均值,这时每一个元素都是一个list的对象
x <- 1:3
lapply(x, mean)
– 举例3:
# 对dataframe使用lapply
df <- data.frame(x=c(1:3),y=c(6:8))
lapply(df, mean)
4. sapply函数
比 lapply 多了一个 simplify 参数。如果 simplify=FALSE ,则等价于lapply 。否则,在上一种情况的基础上,将 lapply 输出的list简化为vector或matrix,默认的simplify=TRUE。
– 举例1:
x<-list(a= 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
#simplify = FALSE,同lapply 返回list对象
sapply(x, mean, simplify = FALSE, USE.NAMES = FALSE)
– 举例2:
#simplify = TRUE,以向量形式返回结果
sapply(x, mean, simplify = TRUE, USE.NAMES = FALSE)
– 举例3:
#默认的simplify=TRUE,fivenum返回多值,因此最终返回结果为matrix对象
sapply(x, fivenum)
5. vapply函数
vapply 类似于 sapply (但返回类型只包含Array) ,但是提供了第三个参数 FUN.VALUE 用以指明返回值的形式,可以看作返回值的模板。vapply会检测FUN的所有值是否与FUN.VALUE兼容,以使他们具有相同的长度和类型,为了实现类型的兼容,类型存在被强制转换为更高类型的可能,转换顺序:
logical < integer < double < complex
– 举例1:
#返回值的类型和长度要和预设值一致
x<-list(a= 1:10, beta = exp(-3:3), logic =c(TRUE,FALSE,FALSE,TRUE))
vapply(x, function(x) {c(mean(x),sd(x))}, FUN.VALUE = c(0, 0), USE.NAMES = TRUE)
6. mapply函数
mapply 是多变量版的 sapply(返回类型只包含Array) ,参数(...)部分可以接收多个数据, mapply 将FUN 应用于这些数据的第一个元素组成的数组,然后是第二个元素组成的数组,以此类推,直到用于每个参数的元素,要求多个数据的长度相同,或者是整数倍关系,如果参数长度不同,长度短的参数会被循环使用。返回值是array或list(如果返回值的向量长度不等,则返回List对象),取决于 FUN 返回值是一个还是多个。
– 举例1:
#对两个list对象的元素依次求和
mapply(sum, list(a=1,b=2,c=3), list(a=10,b=20,d=30))
– 举例2:
#对第一和第二个对象使用rep函数,对象二长度较短会被循环使用
#返回对象长度不同,返回list对象
mapply(rep, c(1,2,4,5), c(3,4))
#返回对象长度相同同,返回matrix对象
mapply(rep, c(1,2,4,5), c(3,4))
– 举例3:
#函数返回多值,因此返回matrix对象
mapply(function(x,y) c(x+y, x^y), c(1:5), c(1:5))
– 举例4:
#使用MoreArgs给出rep的参数x值
mapply(rep, times = 1:2, MoreArgs = list(x = 42))
7. rapply函数
- rapply 是递归版的 lappy 。基本原理是对list作遍历,如果其中有的元素仍然是list,则继续遍历;对于每个非list类型的元素,如果其类型是 classes 参数指定的类型之一,则调用 FUN 。classes="ANY"表示匹配所有类型。how参数用来指定操作方式,有三种:"replace"对元素类型在 classes 中的直接用调用 FUN,不在的保留原始值。
- "list" 新建一个list,元素类型在 classes 中的,调用 FUN ;不在 classes 中的类型,使用 deflt 。会保留原始list的结构。
- "unlist" 相当于对"list"模式下的结果调用 unlist(recursive=TRUE)
– 举例1:
X <- list(list(a = pi, b =list(c = 2)), d = "a test")
#对X中的numeric类型的元素使用sqrt函数,保留非numeric元素值不变
rapply(X, sqrt, classes = "numeric", how ="replace")
– 举例2:
#对X中的character类型的元素使用nchar函数,保留非nchar元素值不变
rapply(X, nchar, classes = "character", how ="replace")
– 举例3:
#对X中的character类型的元素使用nchar函数,非character元素使用默认值deflt
rapply(X, nchar, classes = "character", deflt =as.integer(NA), how = "list")
– 举例4:
#对X中的character类型的元素使用nchar函数,非character元素使用默认值deflt,返回结果使用unlist函数
rapply(X, nchar, classes = "character", deflt =as.integer(NA), how = "unlist")
– 举例5:
#对X中的character类型的元素使用nchar函数,没有设置deflt参数会直接舍弃非character元素,返回结果使用unlist函数
rapply(X, nchar, classes = "character", how ="unlist")
#对于how=list的情况,没有设置deflt参数会使用默认值NULL
rapply(X, nchar, classes = "character", how = "list")
– 举例6:
#对X中的numeric类型的元素使用log函数,函数参数为base=2
rapply(X, log, classes = "numeric", how ="replace", base = 2)
8. eapply函数
对environment中命名值进行FUN计算后返回一个列表值,用户可以请求所有使用过的命名对象。
– 举例1:
env <- new.env(hash = FALSE)
env$a <- 1:10
env$beta <- exp(-3:3)
env$logic <- c(TRUE, FALSE, FALSE, TRUE)
# 列出环境中的对象
utils::ls.str(env)
# 对每个元素计算均值
eapply(env, mean)
各方法详细总结见下表:
函数 |
用法 |
输入 |
输出 |
语法 |
apply |
对阵列行或者列使用函数 |
Array |
Array/List |
apply(X, MARGIN, FUN, ...) |
lapply |
对列表或者向量使用函数 |
List/expression |
List |
lapply(X, FUN, ...) |
sapply |
对列表或者向量使用函数 |
List/expression |
List/Array |
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) |
vapply |
对列表或者向量使用函数 |
List/expression |
Array |
vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE) |
tapply |
对不规则阵列使用函数 |
Array |
Array/List |
tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE) |
eapply |
对环境中的值使用函数 |
Values in an Environment |
List |
eapply(env, FUN, ..., all.names = FALSE, USE.NAMES = TRUE) |
mapply |
对多个列表或者向量参数使用函数 |
List/Array |
List/Array |
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) |
rapply |
运用函数递归产生列表 |
List |
List/Vector |
rapply(object, f, classes = "ANY", deflt = NULL,how = c("unlist", "replace", "list"), ...) |