我正在尝试将data.frame中的一组变量/值传递给map
函数,但不确定如何处理.x
指的是需要要评估:mutate(df2 = map2(variable, value, ~filter(df1, .x==.y)))
天真的!!.x
将不起作用。
这是我的data.frame,其中一列是变量,一列是 value ,将被映射到过滤器调用中:
tibble(variable=c("wool", "tension"),
value= c("A", "L"))
#> # A tibble: 2 x 2
#> variable value
#> <chr> <chr>
#> 1 wool A
#> 2 tension L
如何将它们传递给过滤器?我应该改为声明变量作为担保吗?我尝试了几种方法:
library(tidyverse)
data(warpbreaks)
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, ~filter(warpbreaks, .x==.y)))
#> # A tibble: 2 x 3
#> variable value data_filtered
#> <chr> <chr> <list>
#> 1 wool A <data.frame [0 × 3]>
#> 2 tension L <data.frame [0 × 3]>
tibble(variable=c(quo(wool), quo(tension)),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, ~filter(warpbreaks, eval_tidy(.x)==.y)))
#> Error in eval_tidy(.x): object 'wool' not found
答案 0 :(得分:1)
对.x
的匿名函数求值仍然很奇怪。老实说,我不确定是什么,但是在map2
调用之外定义一个函数似乎可以正常工作(将~ filter(df1, !!sym(.x) == .y)
位分配给@Lionel Henry:
library(tidyverse)
df <- tibble(variable=c("wool", "tension"),
value= c("A", "L"))
data(warpbreaks)
# doesn't work with anonymous function
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, ~ filter(warpbreaks, !!sym(.x) == .y)))
#> Error in is_symbol(x): object '.x' not found
# works when you define function outside of map2
temp <- function(x, y, data){
filter(data, !!sym(x) == y)
}
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, temp, warpbreaks))
#> # A tibble: 2 x 3
#> variable value data_filtered
#> <chr> <chr> <list>
#> 1 wool A <data.frame [27 x 3]>
#> 2 tension L <data.frame [18 x 3]>
由reprex package(v0.2.1)于2019-05-07创建
您也可以在没有外部定义函数的情况下执行以下操作:
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered = map2(variable, value, ~ filter(..3, ..3[[..1]] == ..2), warpbreaks))
#> # A tibble: 2 x 3
#> variable value data_filtered
#> <chr> <chr> <list>
#> 1 wool A <data.frame [27 x 3]>
#> 2 tension L <data.frame [18 x 3]>
答案 1 :(得分:1)
在您的示例中,您尝试以嵌套方式使用dplyr动词:filter()
中有一个mutate()
。这对于正常使用来说效果很好,但是在使用整齐的评估功能时我们需要稍加小心,因为它们在调用外部函数时就很早就应用了。因此,如果您尝试在内部动词中使用!!
或.data
,通常会出现时序问题。
@zack的答案显示了如何分两步分解问题以避免嵌套问题。在这种情况下,另一种可能性是通过直接映射到mutate()
上来省去df
步骤(该想法归功于@Spacedman)。在这里,我们将使用pmap()
并行映射到列表或数据框:
# For pretty-printing
options(tibble.print_max = 5, tibble.print_min = 5)
warpbreaks <- as_tibble(warpbreaks)
pmap(df, ~ filter(warpbreaks, .data[[.x]] == .y))
#> [[1]]
#> # A tibble: 27 x 3
#> breaks wool tension
#> <dbl> <fct> <fct>
#> 1 26 A L
#> 2 30 A L
#> 3 54 A L
#> 4 25 A L
#> 5 70 A L
#> # … with 22 more rows
#>
#> [[2]]
#> # A tibble: 18 x 3
#> breaks wool tension
#> <dbl> <fct> <fct>
#> 1 26 A L
#> 2 30 A L
#> 3 54 A L
#> 4 25 A L
#> 5 70 A L
#> # … with 13 more rows
答案 2 :(得分:1)
您可以使用R
的本机替换工具, rlang 在处理环境时更有价值,但对于更复杂的符号替换(例如嵌套),R基础更容易(对我来说)至少)。
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, ~eval(bquote(
filter(warpbreaks, .(sym(.x)) ==.y)))))
tibble(variable=c("wool", "tension"),
value= c("A", "L")) %>%
mutate(data_filtered=map2(variable, value, ~eval(substitute(
filter(warpbreaks, X ==.y), list(X = sym(.x))))))
# output for either
# # A tibble: 2 x 3
# variable value data_filtered
# <chr> <chr> <list>
# 1 wool A <data.frame [27 x 3]>
# 2 tension L <data.frame [18 x 3]>