10.3 map系列函数
10.3.1 用法
map()
返回列表(list)map_lgl()
,map_int()
,map_dbl()
,map_chr()
返回指定类型的原子向量,即逻辑型,整数型,实数型,字符型等。map_dfr()
和map_dfc()
返回通过指定的行连接或列连接创建的数据框(data.frame)
map(.x, .f, ...)
map_lgl(.x, .f, ...)
map_chr(.x, .f, ...)
map_int(.x, .f, ...)
map_dbl(.x, .f, ...)
map_raw(.x, .f, ...)
map_dfr(.x, .f, ..., .id = NULL)
map_dfc(.x, .f, ...)
在 purrr 中,参数.f
可以是一个 function,formula or vector,像 ~ .x + 2 这种形式的公式会被转换成 function 使用,关于参数的引用有如下三种方式:
- 对一个参数,使用 . 即可
- 两个参数,使用 .x 和 .y
- 对于更多参数,使用..1,..2,..3等等
对于像 ~ .x + 2 会转换成:
function(x){
+ 2
x
}#> function(x){
#> x + 2
#> }
# ~ .x + . y
function(x,y){
+ y
x
}#> function(x,y){
#> x + y
#> }
<- list(1, 1, 1)
x <- list(10, 20, 30)
y <- list(100, 200, 300)
z
pmap(list(x,y,z),~ (..1 + ..2 ) * ..3)
#> [[1]]
#> [1] 1100
#>
#> [[2]]
#> [1] 4200
#>
#> [[3]]
#> [1] 9300
~ (..1 + ..2 ) * ..3转换成:
function(x,y,z){
+ y) * z
(x
}#> function(x,y,z){
#> (x + y) * z
#> }
# pmap 实现
pmap(list(x,y,z),function(x,y,z) ( x + y ) *z)
#> [[1]]
#> [1] 1100
#>
#> [[2]]
#> [1] 4200
#>
#> [[3]]
#> [1] 9300
对于 purrr 风格的公式,我们可以看自己心情,可以学习这种方式也可以不学,因为用 R 里面的 function 也可以完全满足需求
- map_chr
map_chr(.x, .f)
,map_chr 返回对象为字符串
map_chr(letters,paste,'yufei-world',sep='-')
#> [1] "a-yufei-world" "b-yufei-world" "c-yufei-world" "d-yufei-world"
#> [5] "e-yufei-world" "f-yufei-world" "g-yufei-world" "h-yufei-world"
#> [9] "i-yufei-world" "j-yufei-world" "k-yufei-world" "l-yufei-world"
#> [13] "m-yufei-world" "n-yufei-world" "o-yufei-world" "p-yufei-world"
#> [17] "q-yufei-world" "r-yufei-world" "s-yufei-world" "t-yufei-world"
#> [21] "u-yufei-world" "v-yufei-world" "w-yufei-world" "x-yufei-world"
#> [25] "y-yufei-world" "z-yufei-world"
10.3.2 案例
- map
map()
函数返回列表,如下:
1:10 %>%
map(rnorm, n = 10)
# 用匿名函数
1:10 %>%
map(function(x) rnorm(10, x))
# purrr 风格公式
1:10 %>%
map(~ rnorm(10, .x))
使用map()
提取列表对象中的列表元素:
<- list(
l2 list(num = 1:3, letters[1:3]),
list(num = 101:103, letters[4:6]),
list()
)%>% map(c(2, 2))
l2 #> [[1]]
#> [1] "b"
#>
#> [[2]]
#> [1] "e"
#>
#> [[3]]
#> NULL
提取每个列表中的元素,上述代码表示提取列表中第二个对象的第二位置的元素:
list(num = 1:3,letters[1:3])[[2]][2]
#> [1] "b"
list(num = 101:103, letters[4:6])[[2]][2]
#> [1] "e"
通过list构建由“名称”和“数字”构建的提取器提取元素:
%>% map(list("num", 3))
l2 #> [[1]]
#> [1] 3
#>
#> [[2]]
#> [1] 103
#>
#> [[3]]
#> NULL
%>% map_int(list("num", 3), .default = NA)
l2 #> [1] 3 103 NA
- map_dbl
map_dbl()
返回数字向量(双精度)。
1:10 %>%
map(rnorm, n = 10) %>% #输出列表
map_dbl(mean)
#> [1] 0.559 1.821 2.876 4.152 5.116 6.127 6.911 8.281 9.237 10.627
在数据框上应用,由于数据框(data.frame)可以看成是特殊的列表,df[[1]],df[[2]],df[[3]]等。
%>% map_dbl(sum)
mtcars #> mpg cyl disp hp drat wt qsec vs am gear carb
#> 643 198 7383 4694 115 103 571 14 13 118 90
上述计算可以理解为计算:sum(mtcars[[1]]),sum(mtcars[[2]]),sum(mtcars[[3]])等。
- map_chr
map_chr()
返回字符向量。
c("foo", "bar") %>% map_chr(paste0, ":suffix")
#> [1] "foo:suffix" "bar:suffix"
<- list(Sophia = "banana bread", Eliott = "pancakes", Karina = "chocolate cake")
favorite_desserts %>% map_chr(~ paste(.x, "rocks!"))
favorite_desserts #> Sophia Eliott Karina
#> "banana bread rocks!" "pancakes rocks!" "chocolate cake rocks!"
- map_int
通过名字或者是数字位置提取内容。
<- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
l1 %>% map("a", .default = "???")
l1 #> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] "???"
#>
#> [[3]]
#> [1] "???"
%>% map_int("b", .default = NA)
l1 #> [1] NA 2 3
%>% map_int(2, .default = NA)
l1 #> [1] NA 2 NA
- map_df
map_df(.x, .f)
,map_df 返回对象为数据框,类似函数 map_dfr(.x,.f)
,map_dfc(.x,.f)
map_df()函数示例
map_df(c(1, 4, 7), function(.x) {
return(data.frame(old_number = .x,
new_number = addTen(.x)))
})#> old_number new_number
#> 1 1 11
#> 2 4 14
#> 3 7 17
<- function(x){
make_dataframe data.frame(old_number = x,new_number = addTen(x))
}
map_dfr(c(1,4,7),make_dataframe)
#> old_number new_number
#> 1 1 11
#> 2 4 14
#> 3 7 17
在数据导入导出章节中提到的批量读取,通过指定全部要读取的文件列表,使用map_dfr()
函数读取全部文件并合并数据源。
<- list.files(path = './data/read-write/',pattern = '^[a-z].xlsx$',full.names = T)
allfiles ::map_dfr(allfiles,read_excel) purrr
在我实际工作中,实现传统零售行业门店之间商品调拨时就可使用该函数,更多详细信息可以查看我的语雀笔记。