purrr 替代循环
1 purrr循环引用知乎张敬信的说法: ❝用 R 写 「循环」 从低到高有三种境界:手动 for 循环,apply 函数族,purrr 包泛函式编程。 ❞ R写循环有三个境界: 其中,手动for循环我最常用,apply系列半吊子,purrr函数一窍不通,所以要学习一下。 2 泛函式函数泛函式定义函数的函数成为泛函式,map(x,f)中,map是函数,f也是函数,f是map的参数,那么map就是泛函数。 dat = data.frame(y1 = rnorm(10),y2 = rnorm(10)+10) dat map(dat,mean)
这里,map 是函数,mean 是map 的参数,测试数据: > dat = data.frame(y1 = rnorm(10),y2 = rnorm(10)+10) > dat y1 y2 1 0.5817177 10.355036 2 1.4852696 10.058380 3 1.0901313 11.682624 4 0.2128081 11.119148 5 0.8566806 10.547209 6 0.8843383 9.414661 7 0.4761166 11.070056 8 0.3465340 9.301207 9 1.1130833 10.087095 10 0.6286422 9.983994 > map(dat,mean) $y1 [1] 0.7675322
$y2 [1] 10.36194
如果使用apply 系列的lapply 函数,是这样处理的: > lapply(dat,mean) $y1 [1] 0.7675322
$y2 [1] 10.36194
两者结果完全一致, 所以,这里map和apply都是泛函式函数。 3 map的不同类型这里先模拟数据: > dat = data.frame(x1 =rnorm(10),x2 = rnorm(10),x3 = rnorm(10),x4 = rnorm(10)) > dat x1 x2 x3 x4 1 1.203531098 -0.33361497 -0.05708186 0.9924523 2 -0.340909576 0.22388983 -1.42836870 -0.2116809 3 -1.710778506 0.31278696 0.17518334 0.8943420 4 -0.001525112 0.22099926 -0.62475728 -0.7134268 5 0.229862264 -1.76353518 -1.04137751 0.5086442 6 -0.382215060 0.06071203 -0.86489543 -0.7195158 7 1.175170874 -0.78679427 -0.23324264 -0.4412758 8 0.151216441 -1.09148795 0.54867008 0.1762894 9 -0.017814828 0.51608686 0.04602458 -0.5771657 10 -1.406719653 0.30200433 -0.18020801 0.3050708
4 map应用这里,map函数,支持一元函数 map(dat,max)
4.1 「map2应用」这里map2可以支持二元函数,比如: map2(dat$x1,dat$x2,~max(.x,.y))
上面的.x 和.y 表示dat$x1 , dat$x2 两个元素,~max 表示匿名函数。上面需要用map2 或者pmax ,如果用map 就失败: > map(dat$x1,dat$x2,~max(.x,.y)) [[1]] NULL
[[2]] NULL
4.2 「pmap函数」支持两个,或者两个以上的多元函数,默认是对行进行操作: > pmap(dat,max) [[1]] [1] 1.203531 ……
上面的也可以写为: pmap(dat,~max(..1,..2,..3,..4))
4.3 map不同的后缀*_chr,比如map_chr, map2_chr, pmap_chr等,返回字符
5 匿名函数写法- 二元的map2,可以写为.x,.y,或者..1,..2
- 三元的pmap,可以写为..1,..2,..3,..4
5.1 一元的map下面三种写法是等价的。 - 第一种,是直接调用max函数,不是匿名函数,不需要~符号,默认是对列处理,如果对行处理,可以用
pmap - 第三种,是调用匿名函数,前面需要用~,参数用
..1
map(dat,max) map(dat,~max(.x)) map(dat,~max(..1))
5.2 二元的map2和上面一元map用法一样,下面三种也是等价的: map2(dat$x1,dat$x2, max) map2(dat$x1,dat$x2, ~max(.x,.y)) map2(dat$x1,dat$x2, ~max(..1,..2))
5.3 多元的pmap因为多元的,不会有..x, ..y, ..z表示,只会有..1, ..2, ..3表示,所以下面两种也是等价的: pmap(dat,max) pmap(dat,~max(..1,..2,..3,..4))
6 函数的参数两种写法6.1 直接在函数的函数内部比如,要计算每一列的平均值,允许缺失值,需要用到参数na.rm = T ,可以这样写: > map(dat,~mean(.x,na.rm = T)) $x1 [1] -0.1100182
$x2 [1] -0.2338953
$x3 [1] -0.3660053
$x4 [1] 0.02137338
这里,用到了匿名函数,可以把匿名函数的参数,写在匿名函数里面。 6.2 直接在函数内部写这里,因为map函数的用法是:map(.x, .f, ...),其中 所以,计算每一列的平均值,也可以写为: > map(dat,mean,na.rm=T) $x1 [1] -0.1100182
$x2 [1] -0.2338953
$x3 [1] -0.3660053
$x4 [1] 0.02137338
7 map的用法1:批量建模这里使用我的R包learnasreml 中的MET数据,进行测试。 MET数据是作物两年多点的产量试验数据,这里我们分别对每一个地点的品种进行方差分析。 library(learnasreml) data(MET) head(MET) summary(MET)
> library(learnasreml) > data(MET) > head(MET) Year Location Rep Cul Yield 1 2009 KN 1 EarlyCanada 56.236 2 2009 KN 1 CalhounGray 74.167 3 2009 KN 1 StarbriteF1 32.601 4 2009 KN 1 CrimsonSweet 74.167 5 2009 KN 1 GeorgiaRattlesnake 64.794 6 2009 KN 1 FiestaF1 70.907 > summary(MET) Year Location Rep Cul Yield 2009:200 CI:80 1:100 CalhounGray : 40 Min. : 4.034 2010:200 FL:80 2:100 CrimsonSweet : 40 1st Qu.: 45.166 KN:80 3:100 EarlyCanada : 40 Median : 67.647 SC:80 4:100 FiestaF1 : 40 Mean : 67.473 TX:80 GeorgiaRattlesnake: 40 3rd Qu.: 88.616 Legacy : 40 Max. :180.906 (Other) :160 NA's :3
数据包括: 这里,我们对每一个地点的品种,进行方差分析,常规的做法是: loc1 = MET[MET$Location == "CI",] loc2 = MET[MET$Location == "FL",] loc3 = MET[MET$Location == "KN",] loc4 = MET[MET$Location == "SC",] loc5 = MET[MET$Location == "TX",]
提取每一个地点的数据,单独保存。然后对每一个地点进行方差分析: summary(aov(Yield ~ Cul, data=loc1)) summary(aov(Yield ~ Cul, data=loc2)) summary(aov(Yield ~ Cul, data=loc3)) summary(aov(Yield ~ Cul, data=loc4)) summary(aov(Yield ~ Cul, data=loc5))
如果使用map函数进行批量建模: MET %>% split(.$Location) %>% map(.,~aov(Yield ~ Cul,.) %>% summary)
结果如下: > MET %>% split(.$Location) %>% map(.,~aov(Yield ~ Cul,.) %>% summary) $CI Df Sum Sq Mean Sq F value Pr(>F) Cul 9 8696 966.2 3.193 0.00277 ** Residuals 69 20879 302.6 --- Signif. codes: 0 '***’ 0.001 '**’ 0.01 '*’ 0.05 '.’ 0.1 ' ’ 1 1 observation deleted due to missingness
$FL Df Sum Sq Mean Sq F value Pr(>F) Cul 9 10151 1127.9 1.565 0.143 Residuals 69 49723 720.6 1 observation deleted due to missingness
$KN Df Sum Sq Mean Sq F value Pr(>F) Cul 9 8236 915.1 4.038 0.000338 *** Residuals 70 15863 226.6 --- Signif. codes: 0 '***’ 0.001 '**’ 0.01 '*’ 0.05 '.’ 0.1 ' ’ 1
$SC Df Sum Sq Mean Sq F value Pr(>F) Cul 9 24478 2719.8 5.6 8.42e-06 *** Residuals 70 33996 485.7 --- Signif. codes: 0 '***’ 0.001 '**’ 0.01 '*’ 0.05 '.’ 0.1 ' ’ 1
$TX Df Sum Sq Mean Sq F value Pr(>F) Cul 9 5784 642.6 1.326 0.24 Residuals 69 33429 484.5 1 observation deleted due to missingness
8 walk与map对比walk和map函数组合上类似,不同的是walk不返回结果,比如你要保存数据时,就可以用walk函数系列。 上面的MET数据,我们可以将数据按照品种分组,批量的保存名为地点的数据csv中。 data(MET) head(MET) MET %>% group_nest(Location) %>% pwalk(~ write.csv(.y,paste0(.x,".csv")))
结果,每个地点都有一个csv文件: 9 map函数用法2:批量读取数据上面的csv文件,批量读取,然后合并再一起 re = map_dfr(file,read.csv)
10 参考:https://zhuanlan.zhihu.com/p/168772624 https://mp.weixin.qq.com/s/H6nwbkePeeMhDCEwlC1PUA
|