如何在 `mutate` 中的 `map` 中取消引号 (!!)
how to unquote (!!) inside `map` inside `mutate`
我正在使用 map2
和 mutate
修改 foo
内的嵌套数据框,我想根据 [= 在每个嵌套数据框中命名一个变量16=]。我不确定 nse
/tidyeval
取消引号的正确语法是什么。
我的尝试:
library(tidyverse)
foo <- mtcars %>%
group_by(gear) %>%
nest %>%
mutate(name = c("one", "two", "three")) %>%
mutate(data = map2(data, name, ~
mutate(.x, !!(.y) := "anything")))
#> Error in quos(...): object '.y' not found
我希望嵌套数据框中新创建的变量的名称分别为 "one"、"two" 和 "three"。
我的尝试基于我在正常 df
上执行正常 mutate
时使用的正常语法,其中 name
是一个字符串:
name <- "test"
mtcars %>% mutate(!!name := "anything") # works fine
如果成功,下面一行应该return TRUE
:
foo[1,2] %>% unnest %>% names %>% .[11] == "one"
这似乎是 feature/bug(不确定,请参阅下面链接的 GitHub 问题)!!
如何在 mutate
和 map
中工作。解决方案是定义一个自定义函数,在这种情况下取消引用会按预期工作。
library(tidyverse)
custom_mutate <- function(df, name, string = "anything")
mutate(df, !!name := string)
foo <- mtcars %>%
group_by(gear) %>%
nest %>%
mutate(name = c("one", "two", "three")) %>%
mutate(data = map2(data, name, ~
custom_mutate(.x, .y)))
foo[1,2] %>% unnest %>% names %>% .[11] == "one"
#[1] TRUE
您可以在问题 #541 下找到有关 GitHub 的更多详细信息:map2() call in dplyr::mutate() error while standalone map2() call works;请注意,该问题已于 2018 年 9 月关闭,因此我假设这是预期的行为。
另一种方法可能是使用 group_split
而不是 nest
,在这种情况下我们
避免取消引用问题
nms <- c("one", "two", "three")
mtcars %>%
group_split(gear) %>%
map2(nms, ~.x %>% mutate(!!.y := "anything"))
这是因为取消引用的时机。嵌套 tidy eval 函数可能有点棘手,因为它是第一个处理取消引用运算符的 tidy eval 函数。
让我们改写一下:
mutate(data = map2(data, name, ~ mutate(.x, !!.y := "anything")))
至
mutate(data = map2(data, name, function(x, y) mutate(x, !!y := "anything")))
x
和 y
绑定仅在函数被 map2()
调用时创建。因此,当第一个 mutate()
运行时,这些绑定尚不存在,您会收到一个对象未找到错误。使用公式有点难看,但公式扩展为采用 .x
和 .y
参数的函数,因此我们遇到了同样的问题。
一般来说,最好避免在您的代码中使用复杂的嵌套逻辑,因为这会增加代码的可读性。使用 tidy eval 会更加复杂,因此最好分步进行。作为一个额外的好处,按步骤做事需要创建中间变量,如果命名得当,有助于理解函数在做什么。
我正在使用 map2
和 mutate
修改 foo
内的嵌套数据框,我想根据 [= 在每个嵌套数据框中命名一个变量16=]。我不确定 nse
/tidyeval
取消引号的正确语法是什么。
我的尝试:
library(tidyverse)
foo <- mtcars %>%
group_by(gear) %>%
nest %>%
mutate(name = c("one", "two", "three")) %>%
mutate(data = map2(data, name, ~
mutate(.x, !!(.y) := "anything")))
#> Error in quos(...): object '.y' not found
我希望嵌套数据框中新创建的变量的名称分别为 "one"、"two" 和 "three"。
我的尝试基于我在正常 df
上执行正常 mutate
时使用的正常语法,其中 name
是一个字符串:
name <- "test"
mtcars %>% mutate(!!name := "anything") # works fine
如果成功,下面一行应该return TRUE
:
foo[1,2] %>% unnest %>% names %>% .[11] == "one"
这似乎是 feature/bug(不确定,请参阅下面链接的 GitHub 问题)!!
如何在 mutate
和 map
中工作。解决方案是定义一个自定义函数,在这种情况下取消引用会按预期工作。
library(tidyverse)
custom_mutate <- function(df, name, string = "anything")
mutate(df, !!name := string)
foo <- mtcars %>%
group_by(gear) %>%
nest %>%
mutate(name = c("one", "two", "three")) %>%
mutate(data = map2(data, name, ~
custom_mutate(.x, .y)))
foo[1,2] %>% unnest %>% names %>% .[11] == "one"
#[1] TRUE
您可以在问题 #541 下找到有关 GitHub 的更多详细信息:map2() call in dplyr::mutate() error while standalone map2() call works;请注意,该问题已于 2018 年 9 月关闭,因此我假设这是预期的行为。
另一种方法可能是使用 group_split
而不是 nest
,在这种情况下我们
避免取消引用问题
nms <- c("one", "two", "three")
mtcars %>%
group_split(gear) %>%
map2(nms, ~.x %>% mutate(!!.y := "anything"))
这是因为取消引用的时机。嵌套 tidy eval 函数可能有点棘手,因为它是第一个处理取消引用运算符的 tidy eval 函数。
让我们改写一下:
mutate(data = map2(data, name, ~ mutate(.x, !!.y := "anything")))
至
mutate(data = map2(data, name, function(x, y) mutate(x, !!y := "anything")))
x
和 y
绑定仅在函数被 map2()
调用时创建。因此,当第一个 mutate()
运行时,这些绑定尚不存在,您会收到一个对象未找到错误。使用公式有点难看,但公式扩展为采用 .x
和 .y
参数的函数,因此我们遇到了同样的问题。
一般来说,最好避免在您的代码中使用复杂的嵌套逻辑,因为这会增加代码的可读性。使用 tidy eval 会更加复杂,因此最好分步进行。作为一个额外的好处,按步骤做事需要创建中间变量,如果命名得当,有助于理解函数在做什么。