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){
x + 2
}
#> function(x){
#> x + 2
#> }
# ~ .x + . y
function(x,y){
x + y
}
#> function(x,y){
#> x + y
#> }x <- list(1, 1, 1)
y <- list(10, 20, 30)
z <- list(100, 200, 300)
pmap(list(x,y,z),~ (..1 + ..2 ) * ..3)
#> [[1]]
#> [1] 1100
#>
#> [[2]]
#> [1] 4200
#>
#> [[3]]
#> [1] 9300~ (..1 + ..2 ) * ..3转换成:
function(x,y,z){
(x + y) * z
}
#> 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()提取列表对象中的列表元素:
l2 <- list(
list(num = 1:3, letters[1:3]),
list(num = 101:103, letters[4:6]),
list()
)
l2 %>% map(c(2, 2))
#> [[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构建由“名称”和“数字”构建的提取器提取元素:
l2 %>% map(list("num", 3))
#> [[1]]
#> [1] 3
#>
#> [[2]]
#> [1] 103
#>
#> [[3]]
#> NULL
l2 %>% map_int(list("num", 3), .default = NA)
#> [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]]等。
mtcars %>% map_dbl(sum)
#> 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"
favorite_desserts <- list(Sophia = "banana bread", Eliott = "pancakes", Karina = "chocolate cake")
favorite_desserts %>% map_chr(~ paste(.x, "rocks!"))
#> Sophia Eliott Karina
#> "banana bread rocks!" "pancakes rocks!" "chocolate cake rocks!"- map_int
通过名字或者是数字位置提取内容。
l1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))
l1 %>% map("a", .default = "???")
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] "???"
#>
#> [[3]]
#> [1] "???"
l1 %>% map_int("b", .default = NA)
#> [1] NA 2 3
l1 %>% map_int(2, .default = NA)
#> [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
make_dataframe <- function(x){
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()函数读取全部文件并合并数据源。
allfiles <- list.files(path = './data/read-write/',pattern = '^[a-z].xlsx$',full.names = T)
purrr::map_dfr(allfiles,read_excel)在我实际工作中,实现传统零售行业门店之间商品调拨时就可使用该函数,更多详细信息可以查看我的语雀笔记。