map(映射)與reduce(規(guī)約)操作在數(shù)據(jù)處理中非常常見,R語(yǔ)言的核心是向量化操作,自帶的apply系列函數(shù)完成了數(shù)據(jù)框的向量化計(jì)算,而purrr包中的map與reduce系列函數(shù)很好的拓展了向量化計(jì)算,使R語(yǔ)言處理數(shù)據(jù)更加優(yōu)雅流暢。
purrr包是tidyverse系列中的包,開發(fā)者是大名鼎鼎的Hadley Wickham。purrr包中的函數(shù)很多,使用最多的是map與reduce系列函數(shù)。
安裝包
install.packages('purrr')
map
map表示映射,可以在一個(gè)或多個(gè)列表/向量的每個(gè)位置上應(yīng)用相同函數(shù)進(jìn)行計(jì)算。map函數(shù)的映射對(duì)象只有一個(gè)。

map(.x, .f, ...)
.x: 列表或向量;
.f: 映射函數(shù);
...: 映射函數(shù)的其他參數(shù)
# 加載包
library(purrr)
# 單個(gè)向量map
1:4 %>%
map(rnorm)
## [[1]]
## [1] 0.1892454
##
## [[2]]
## [1] -1.149757 1.782667
##
## [[3]]
## [1] 0.9311241 0.5962078 0.8575180
##
## [[4]]
## [1] 1.2708588 0.7957794 -0.0106283 0.5393979
從map函數(shù)的結(jié)果來(lái)看,其返回與輸入向量等長(zhǎng)的結(jié)果,類型為列表。
其他參數(shù)
可以指定映射函數(shù)的其他參數(shù):
# 單個(gè)向量map,指定函數(shù)參數(shù)
1:4 %>%
map(rnorm,mean=1,sd=2)
## [[1]]
## [1] 1.610763
##
## [[2]]
## [1] -0.4034499 1.5814313
##
## [[3]]
## [1] 2.806429 1.719962 2.005490
##
## [[4]]
## [1] 2.170663 2.849836 1.085069 4.130320
匿名函數(shù)
傳入的函數(shù)可以是匿名函數(shù):
# 單個(gè)向量map,使用匿名函數(shù)
1:4 %>%
map(function(x) rnorm(x))
## [[1]]
## [1] 0.01422782
##
## [[2]]
## [1] 1.7895586 0.7135593
##
## [[3]]
## [1] 0.0603224 1.0498781 -1.0028828
##
## [[4]]
## [1] 0.2673761 -1.1297717 0.7769814 1.5304043
公式函數(shù)
還可以把函數(shù)當(dāng)成一個(gè)公式傳入,這是purrr提供的高級(jí)功能,能夠簡(jiǎn)化代碼量。
- 當(dāng)函數(shù)只有一個(gè)參數(shù)時(shí),公式函數(shù)中用
.x代替參數(shù); - 當(dāng)函數(shù)有兩個(gè)參數(shù)時(shí),公式函數(shù)中用
.x,.y代替參數(shù); - 當(dāng)函數(shù)有多個(gè)參數(shù)時(shí),公式函數(shù)中用
..1,..2,..3代替參數(shù)。
# 單個(gè)向量map,使用公式函數(shù)
1:4 %>%
map(~rnorm(.x))
## [[1]]
## [1] -1.471681
##
## [[2]]
## [1] -0.04243286 -0.68348293
##
## [[3]]
## [1] 1.613470 -0.750001 -1.278718
##
## [[4]]
## [1] 0.9369563 -0.5285622 0.8601058 1.8868754
map2
map2函數(shù)是map函數(shù)的變形,映射對(duì)象有兩個(gè),需要注意兩個(gè)列表/向量的長(zhǎng)度必須相同。

map2(.x,.y, .f, ...)
.x: 列表或向量;
.y: 列表或向量,與.x等長(zhǎng);
.f: 映射函數(shù);
...: 映射函數(shù)的其他參數(shù)
# 兩個(gè)向量map
map2(1:3,2:4,sum)
## [[1]]
## [1] 3
##
## [[2]]
## [1] 5
##
## [[3]]
## [1] 7
用公式函數(shù)的方式:
# 兩個(gè)向量map,使用公式函數(shù)
map2(1:3,2:4,~sum(.x,.y))
## [[1]]
## [1] 3
##
## [[2]]
## [1] 5
##
## [[3]]
## [1] 7
# 兩個(gè)向量map,使用公式函數(shù)
map2(1:3,2:4,~sum(..1,..2))
## [[1]]
## [1] 3
##
## [[2]]
## [1] 5
##
## [[3]]
## [1] 7
pmap
pmap函數(shù)是map函數(shù)的變形,映射對(duì)象為多個(gè),需要注意多個(gè)列表/向量的長(zhǎng)度必須相同。

pmap(.l, .f, ...)
.l: 列表向量/列表;
.f: 映射函數(shù);
...: 映射函數(shù)的其他參數(shù)
# 多個(gè)向量map
pmap(list(1:3,2:4,3:5),sum)
## [[1]]
## [1] 6
##
## [[2]]
## [1] 9
##
## [[3]]
## [1] 12
用公式函數(shù)的方式:
# 多個(gè)向量map,使用公式函數(shù)
pmap(list(1:3,2:4,3:5),~sum(..1,..2,..3))
## [[1]]
## [1] 6
##
## [[2]]
## [1] 9
##
## [[3]]
## [1] 12
map變形
map,map2和pmap返回的數(shù)據(jù)格式都是列表,有時(shí)候需要對(duì)返回的結(jié)果進(jìn)行數(shù)據(jù)格式轉(zhuǎn)換,這時(shí)候可以直接使用map系列的變形函數(shù),直接一步完成。
# 返回列表
map(mtcars,mean)
## $mpg
## [1] 20.09062
##
## $cyl
## [1] 6.1875
##
## $disp
## [1] 230.7219
##
## $hp
## [1] 146.6875
##
## $drat
## [1] 3.596563
##
## $wt
## [1] 3.21725
##
## $qsec
## [1] 17.84875
##
## $vs
## [1] 0.4375
##
## $am
## [1] 0.40625
##
## $gear
## [1] 3.6875
##
## $carb
## [1] 2.8125
使用map_df函數(shù),直接返回?cái)?shù)據(jù)框格式。
# 返回?cái)?shù)據(jù)框
map_df(mtcars,mean)
## # A tibble: 1 x 11
## mpg cyl disp hp drat wt qsec vs am gear carb
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 20.1 6.19 231. 147. 3.60 3.22 17.8 0.438 0.406 3.69 2.81
# 返回字符向量
map_chr(mtcars,mean)
## mpg cyl disp hp drat wt
## "20.090625" "6.187500" "230.721875" "146.687500" "3.596563" "3.217250"
## qsec vs am gear carb
## "17.848750" "0.437500" "0.406250" "3.687500" "2.812500"
其他的有:
-
map_lgl/map2_lgl/pmap_lgl:返回邏輯向量; -
map_int/map2_int/pmap_int:返回整數(shù)向量; -
map_dbl/map2_dbl/pmap_dbl:返回浮點(diǎn)數(shù)向量; -
map_chr/map2_chr/pmap_chr:返回字符串向量。
reduce
reduce函數(shù)表示規(guī)約,計(jì)算向量中相鄰的兩個(gè)元素,結(jié)果再與第三個(gè)元素計(jì)算,...,最后計(jì)算出一個(gè)值。

reduce(.x, .f, ...)
.x: 列表向量/列表;
.f: 規(guī)約函數(shù);
...: 函數(shù)的其他參數(shù)
# 單個(gè)向量reduce
reduce(1:5,paste)
## [1] "1 2 3 4 5"
reduce2
reduce2函數(shù)可以同時(shí)對(duì)兩個(gè)向量進(jìn)行規(guī)約計(jì)算,注意第二個(gè)向量長(zhǎng)度需要比第一個(gè)向量小1。
reduce2(.x, .y,.f, ...)
.x: 列表向量/列表;
.y: 列表向量/列表,長(zhǎng)度比.x小1;
.f: 規(guī)約函數(shù);
...: 函數(shù)的其他參數(shù)
# 多個(gè)向量reduce
reduce2(1:4,c(1,1,1),function(x,y,z) x+y-z)
## [1] 7
計(jì)算邏輯為第一次:1+2-1=2,第二次2+3-1=4,第三次4+4-1=7。
更多的purrr包中函數(shù)用法,可以參考:cheatsheet