2020-05-25 apply函数族
其实也没必要记住这么多,不会用了查就行
lapply
|
|-> 简化版: sapply
| | -> 可设置返回值模板: vapply
| |-> 多变量版: mapply
|
|-> 递归版: rapply
apply
-
3个参数,(data,margin,FUN)
-
应用在matrix或array上
sweep
常常和apply一起用,sweep函数和apply函数相似,但是sweep主要用于array的计算,而apply更多的是矩阵和data.frame计算。
mean.att <- apply(attitude, 2, mean)
sweep(attitude, 2, mean.att, FUN = "-") %>% head()
tapply和aggregate
tapply函数很有用,tapply的功能就是把数据按照某种分组,在每个组内进行某个运算。这个aggregate函数很像。我觉得还是aggregate好用。
> aggregate(mtcars,by=list(mtcars$cyl,mtcars$gear),FUN=mean)
...略
> aggregate(mtcars,by=list(mtcars$gear),FUN=mean)
Group.1 mpg cyl disp hp drat wt qsec vs am
1 3 16.10667 7.466667 326.3000 176.1333 3.132667 3.892600 17.692 0.2000000 0.0000000
2 4 24.53333 4.666667 123.0167 89.5000 4.043333 2.616667 18.965 0.8333333 0.6666667
3 5 21.38000 6.000000 202.4800 195.6000 3.916000 2.632600 15.640 0.2000000 1.0000000
gear carb
1 3 2.666667
2 4 2.333333
3 5 4.400000
> aggregate(mtcars$qsec,by=list(mtcars$gear),FUN=mean)
Group.1 x
1 3 17.692
2 4 18.965
3 5 15.640
> aggregate(cbind(mpg,hp) ~ cyl+gear, FUN=mean)
cyl gear mpg hp
1 4 3 21.500 97.0000
2 6 3 19.750 107.5000
3 8 3 15.050 194.1667
4 4 4 26.925 76.0000
5 6 4 19.750 116.5000
6 4 5 28.200 102.0000
7 6 5 19.700 175.0000
8 8 5 15.400 299.5000
> tapply(mtcars$qsec,mtcars$gear, mean)
3 4 5
17.692 18.965 15.640
还可以实现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)
loc
year beijing shanghai
2001 3 7
2002 11 15
2003 19 23
# 类似的aggregate就麻烦一些
> aggregate(df$sale, by = list(df$year,df$loc),FUN= sum) %>%
+ reshape2::dcast(Group.1~Group.2)
Group.1 beijing shanghai
1 2001 3 7
2 2002 11 15
3 2003 19 23
sapply和lapply
-
都只有两个参数,第一个参数是输入数据,第二个是函数。
-
都应用在一个vector或list上
-
sapply返回的是一个vector,但是lapply返回的是一个list。其实sapply可以理解成lapply的简化版,s就是simplify的意思。
其它:为了让sapply返回array或matrix,simplify参数很好用。
sapply(1:5,function(x) matrix(x,2,2), simplify = "array")
这两个sapply/lapply 常和unlist(),matrix(),as.dataframe(),函数一起使用
mapply
- 多变量版的sapply,很好用,m就是multi的意思。
- 返回值是vector或matrix
下面这段代码值得一看
Alco <- data.frame(AlcoholDrunk = c( "YES", "YES", "NO", "YES", "YES", "YES", NA, "YES", "YES", "YES", "YES", "YES", "YES", "NO", "NO", "NO", "NO", "YES"),
AmountDrunk = c(3.0, 1.0, NA ,3.0, NA, 0.0, NA, 0.0, NA, 1.7, NA, NA, 0.0, NA, NA, NA, NA, 2.0))
#这里AlcoholDrunk变量有三种类型的值,“YES”,表示有饮酒史;“NO”, 表示无饮酒史;NA, 表示数据不可获取。
# alcohol函数实现的功能是:如果AlcoholDrunk是NA,直接返回NA,如果是NO,返回NO;否则返回AmountDrunk的数值。
alcohol <- function(texVal, numVal){
if(is.na(texVal)) {return("NA")}
else if(texVal == "NO"){return("NO")}
else if(is.na(numVal)){return("amount Unknown")}
else {return(numVal)}
}
mapply(alcohol, Alco$AlcoholDrunk, Alco$AmountDrunk)
replicate
另外还有一个非常有用的函数replicate(),它可以将某个函数重复运行N次,常常用来生成较复杂的随机数。下面的例子即先建立一个函数,模拟扔两个骰子的点数之和,然后重复运行1000次。
# 定义一个game函数
game <- function() {
n <- sample(1:6,2,replace=T) #这个sample()函数也挺有意思的,我想replicate()应该经常会和sample()连用
return(sum(n))
}
replicate(n=1000,game()) #将game()函数重复运行1000次。
rapply
这个好像也非常有用
rapply(list, FUN, classes="ANY", deflt=NULL, how=c("unlist", "replace", "list"), ...)
rapply是递归版的lappy。基本原理是对list作遍历,如果其中有的元素仍然是list,则继续遍历;对于每个非list类型的元素,如果其类型是classes参数指定的类型之一,则调用FUN。classes="ANY"表示匹配所有类型。
how参数用来指定操作方式,有三种:
a. "replace" 直接用调用FUN后的结果替换原list中原来的元素
b. "list" 新建一个list,元素类型在classes中的,调用FUN;不在classes中的类型,使用deflt。会保留原始list的结构。
c. "unlist" 相当于对"list"模式下的结果调用unlist(recursive=TRUE)
看完下面的例子你就明白了
> lst <- list(a=list(aa=c(1:5), ab=c(0.1,0.2,0.25,0.3,0.33)), #a list里两个元素
+ b=list(ba=c(1:10)), #b list里一个元素
+ c=c('ha','m','k')) #c 不是一个list; a,b,c共同构成了lst list
> lst
$a
$a$aa
[1] 1 2 3 4 5
$a$ab
[1] 0.10 0.20 0.25 0.30 0.33
$b
$b$ba
[1] 1 2 3 4 5 6 7 8 9 10
$c
[1] "ha" "m" "k"
> rapply(lst, sum, how='list',classes = 'numeric')
$a
$a$aa
NULL
$a$ab
[1] 1.18
$b
$b$ba
NULL
$c
NULL
> rapply(lst, sum, how='unlist',classes = c('integer'))
a.aa b.ba
15 55
> rapply(lst, sum, how='unlist',classes = c('integer','numeric'))
a.aa a.ab b.ba
15.00 1.18 55.00
> rapply(lst, sum, how='unlist',classes = c('integer','numeric'),deflt="This is deflt")
a.aa a.ab b.ba c
"15" "1.18" "55" "This is deflt"
> rapply(lst, nchar, how='unlist',classes = "character", deflt="DEFLT")
a.aa a.ab b.ba c1 c2 c3
"DEFLT" "DEFLT" "DEFLT" "2" "1" "1"