Purrr包
Hadley Wickham开发的,天生函数式编程范式,可以实现迭代列表,并对每个元素单独应用函数。尽管lapply函数在R的基础包中也都实现了相
Hadley Wickham开发的,天生函数式编程范式,可以实现迭代列表,并对每个元素单独应用函数。
尽管lapply函数在R的基础包中也都实现了相关的迭代功能,但Purrr包的函数在计算时间和编程耗时上更短,能使用管道符进一步操作。而且返回结果也更友好。
map函数
该包的基础函数,将函数应用到列表的每个元素上,并返回相应长度的一个列表。看起来与lapply函数类似,但map函数被设计来进行管道操作。
> theList <- list(A=matrix(1:9,3),B=1:5,C=matrix(1:4,2),D=2)n> lapply(theList,sum)n$An[1] 45nn$Bn[1] 15nn$Cn[1] 10nn$Dn[1] 2
map函数实现类似功能
> library(purrr)n> theList %>% map(sum)n$An[1] 45nn$Bn[1] 15nn$Cn[1] 10nn$Dn[1] 2
测试是否一样
> identical(lapply(theList, sum),theList %>% map(sum))n[1] TRUE
map函数可以用管道操作。
> theList2 <- theListn> theList2[[1]][2,1] <- NAn> theList2[[2]][4] <- NAn> theList2 %>% map(sum)n$An[1] NAnn$Bn[1] NAnn$Cn[1] 10nn$Dn[1] 2
当有NA值时的结果。
> theList2 %>% map(function(x) sum(x,na.rm = T))n$An[1] 43nn$Bn[1] 11nn$Cn[1] 10nn$Dn[1] 2
通过定义匿名函数处理NA值。
> theList2 %>% map( sum,na.rm =TRUE)n$An[1] 43nn$Bn[1] 11nn$Cn[1] 10nn$Dn[1] 2
上面通过为sum函数提供额外的参数来解决NA值。
返回特定类型的map函数
> theList %>% map_int(NROW)nA B C D n3 5 2 1
这个函数对每个元素返回一个整数,如果元素是一维的,返回其长度,如果是二维的,返回其行数。
> theList %>% map_int(mean)n错误: Can't coerce element 1 from a double to a integern>
上面返回结果不符合要求。
> theList %>% map_dbl(mean)n A B C D n5.0 3.0 2.5 2.0
这样就可以。
> theList %>% map(class)n$An[1] "matrix" "array" nn$Bn[1] "integer"nn$Cn[1] "matrix" "array" nn$Dn[1] "numeric"
元素的类型。
> theList %>% map_lgl(function(x) NROW(x) < 3)n A B C D nFALSE FALSE TRUE TRUE
返回逻辑向量。
buildDF <- function(x){n data.frame(A=1:x,B=x:1)} #构建有两列的数据框nnnlistOfLengths <- list(3,4,1,5)nlistOfLengths %>% map(buildDF) #迭代列表,为每个元素创建一个数据框
map函数返回一个长度为4的列表,其中每个元素都是一个数据框。
[[1]]n A Bn1 1 3n2 2 2n3 3 1nn[[2]]n A Bn1 1 4n2 2 3n3 3 2n4 4 1nn[[3]]n A Bn1 1 1nn[[4]]n A Bn1 1 5n2 2 4n3 3 3n4 4 2n5 5 1
下面直接返回数据框类型
> listOfLengths %>% map_df(buildDF)n A Bn1 1 3n2 2 2n3 3 1n4 1 4n5 2 3n6 3 2n7 4 1n8 1 1n9 1 5n10 2 4n11 3 3n12 4 2n13 5 1
map_if在符合某种条件下才对列表中的元素进行修改
> theList %>% map_if(is.matrix,function(x) x*2)n$An [,1] [,2] [,3]n[1,] 2 8 14n[2,] 4 10 16n[3,] 6 12 18nn$Bn[1] 1 2 3 4 5nn$Cn [,1] [,2]n[1,] 2 6n[2,] 4 8nn$Dn[1] 2n
也可以用更formula创建简单的匿名函数,参数形式为.x和.y
> theList %>% map_if(is.matrix,~ .x*2)n$An [,1] [,2] [,3]n[1,] 2 8 14n[2,] 4 10 16n[3,] 6 12 18nn$Bn[1] 1 2 3 4 5nn$Cn [,1] [,2]n[1,] 2 6n[2,] 4 8nn$Dn[1] 2
数据框的迭代
从本质上讲数据框也是列表。计算数据集diamonds中数值型的列的平均。
> data(diamonds,package = 'ggplot2')n> diamonds %>% map_dbl(mean)n carat cut color clarity n 0.7979397 NA NA NA n depth table price x n 61.7494049 57.4571839 3932.7997219 5.7311572 n y z n 5.7345260 3.5387338
非数值列型的列返回NA。
> diamonds %>% summarise_each(funs(mean))n# A tibble: 1 x 10n carat cut color clarity depth table price xn <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>n1 0.798 NA NA NA 61.7 57.5 3933. 5.73n# ... with 2 more variables: y <dbl>, z <dbl>nWarning messages:n1: `summarise_each_()` was deprecated in dplyr 0.7.0.nPlease use `across()` instead.
上述函数返回一个单行数据框,而map_dbl返回一个数值型向量。
map函数的多输入
两个列表的元素作用在函数上
firstList <- list(A=matrix(1:16,4),B=matrix(1:16,2),C=1:5)nsecondList <- list(A=matrix(1:16,4),B=matrix(1:16,8),C=15:1)nsimpleFunc <- function(x,y){n NROW(x)+NROW(y)n}nmap2(firstList,secondList,simpleFunc)nn$An[1] 8nn$Bn[1] 10nn$Cn[1] 20
下面返回整型向量
> map2_int(firstList,secondList,simpleFunc)n A B C n 8 10 20
更一般的pmap函数
> pmap(list(firstList,secondList),simpleFunc)n$An[1] 8nn$Bn[1] 10nn$Cn[1] 20
类似地
> pmap_int(list(firstList,secondList),simpleFunc)n A B C n 8 10 20
参考文献
R for Everyone:Advanced Analytics and Graphics,Lander,Jared著,2017-06-08