采用这个简单的数据集和函数(代表更复杂的问题):
x <- data.frame(a = 1:3, b = 2:4)
mult <- function(a,b,n) (a + b) * n
Run Code Online (Sandbox Code Playgroud)
使用base R Map我可以这样做以向量化方式添加2个新列:
ns <- 1:2
x[paste0("new",seq_along(ns))] <- Map(mult, x["a"], x["b"], n=ns)
x
# a b new1 new2
#1 1 2 3 6
#2 2 3 5 10
#3 3 4 7 14
Run Code Online (Sandbox Code Playgroud)
purrr尝试通过pmap列表输出接近:
library(purrr)
library(dplyr)
x %>% select(a,b) %>% pmap(mult, n=1:2)
#[[1]]
#[1] 3 6
#
#[[2]]
#[1] 5 10
#
#[[3]]
#[1] 7 14
Run Code Online (Sandbox Code Playgroud)
我尝试pmap_dfr将此映射回新列时似乎错误了.
我如何最终制作两个与我当前相匹配的变量"new1"/"new2"?我确信有一个简单的咒语,但我显然忽略它或使用错误的*map*功能.
这里有一些有用的讨论 - 如何使用purrr中的map和dplyr :: mutate来创建基于列对的多个新列 - 但是对于我想象的这个简单的问题来说它看起来过于hacky和不灵活.
我发现的最好的方法(仍然不是很优雅)是通过管道传输到bind_cols. 为了pmap_dfr正确工作,该函数应该返回一个命名列表(可能是也可能不是数据框):
library(tidyverse)
x <- data.frame(a = 1:3, b = 2:4)
mult <- function(a,b,n) as.list(set_names((a + b) * n, paste0('new', n)))
x %>% bind_cols(pmap_dfr(., mult, n = 1:2))
#> a b new1 new2
#> 1 1 2 3 6
#> 2 2 3 5 10
#> 3 3 4 7 14
Run Code Online (Sandbox Code Playgroud)
为了避免更改 的定义mult,您可以将其包装在匿名函数中:
mult <- function(a,b,n) (a + b) * n
x %>% bind_cols(pmap_dfr(
.,
~as.list(set_names(
mult(...),
paste0('new', 1:2)
)),
n = 1:2
))
#> a b new1 new2
#> 1 1 2 3 6
#> 2 2 3 5 10
#> 3 3 4 7 14
Run Code Online (Sandbox Code Playgroud)
不过,在这种特殊情况下,实际上没有必要迭代行,因为您可以对 的输入进行矢量化x,然后迭代n。优点是通常n > p,因此迭代次数会[可能低很多]。需要明确的是,这种方法是否可行取决于函数可以接受哪些参数的向量参数。
mult仍然需要调用 的变量x。最简单的方法是显式传递它们:
x %>% bind_cols(map_dfc(1:2, ~mult(x$a, x$b, .x)))
#> a b V1 V2
#> 1 1 2 3 6
#> 2 2 3 5 10
#> 3 3 4 7 14
Run Code Online (Sandbox Code Playgroud)
pmap...但这失去了命名变量将自动传递给正确参数的好处。您可以通过使用来恢复它purrr::lift,这是一个副词,可以更改函数的域,以便它通过将列表包装在 中来接受列表do.call。可以调用返回的函数以及该迭代x的值:n
x %>% bind_cols(map_dfc(1:2, ~lift(mult)(x, n = .x)))
Run Code Online (Sandbox Code Playgroud)
这相当于
x %>% bind_cols(map_dfc(1:2, ~invoke(mult, x, n = .x)))
Run Code Online (Sandbox Code Playgroud)
但前者的优点是它返回一个可以partial应用的函数x,因此它只剩下一个n参数,因此不需要显式引用x,因此管道更好:
x %>% bind_cols(map_dfc(1:2, partial(lift(mult), .)))
Run Code Online (Sandbox Code Playgroud)
全部返回相同的东西。%>% set_names(~sub('^V(\\d+)$', 'new\\1', .x))如果您愿意,可以在事后使用 来修复名称。
| 归档时间: |
|
| 查看次数: |
773 次 |
| 最近记录: |