在 `dplyr` 的 `across()` 中评估 constants/scalars
Evaluating constants/scalars inside `dplyr`'s `across()`
在我看来,这似乎是一件相当容易的事情,但我在尝试让它发挥作用时遇到了很多麻烦。
我想通过 mutate()
和 across()
做的只是让一些变量在自定义函数中计算为常量或标量。
我将使用非across()
实现来演示:
library(dplyr, warn.conflicts = FALSE)
vars <- c("mpg", "cyl")
Test_Function <- function(.data, .vars) {
Data_Frame <- .data %>%
mutate(
!!.vars[1] := "Something",
!!.vars[2] := 2L
) %>%
select({{.vars}}) %>%
as_tibble()
return(Data_Frame)
}
mtcars %>% Test_Function(vars)
#> # A tibble: 32 x 2
#> mpg cyl
#> <chr> <int>
#> 1 Something 2
#> 2 Something 2
#> 3 Something 2
#> 4 Something 2
#> 5 Something 2
#> 6 Something 2
#> 7 Something 2
#> 8 Something 2
#> 9 Something 2
#> 10 Something 2
#> # ... with 22 more rows
由 reprex package (v2.0.1)
于 2021-08-11 创建当我试图通过 across()
完成同样的事情时,我无法让它工作:
library(dplyr, warn.conflicts = FALSE)
vars <- c("mpg", "cyl")
Test_Function <- function(.data, .vars) {
Data_Frame <-
.data %>%
mutate(
across(!!.vars, "Something"), # Doesn't work
across(!!.vars, ~ .x := "Something"), # purrr-style doesn't work
across(!!.vars, ~ assign(.x, "Something")), # purrr-style with assign() doesn't work
across(!!.vars, assign, "Something") # Regular assign() doesn't work
) %>%
select({{.vars}}) %>%
as_tibble()
return(Data_Frame)
}
mtcars %>% Test_Function(vars)
顺便说一句,我希望我可以提供 across()
一些 .data
中不存在的变量,这样我就可以轻松地创建 new 列而无需必须在 mutate()
内手动完成,但截至撰写本文时还行不通(还?)。
编辑:
@MrFlick/@JonSpring 和@TimTeaFan 给出了对我有用的建议;前者仅用于一个值,后者用于值列表。我将为我所使用的两者提供最少的代表。谢谢大家的帮助!
@MrFlick/@JonSpring的建议,返回单个值:
library(dplyr, warn.conflicts = FALSE)
vars <- c("mpg", "cyl")
Test_Function <- function(.data, .vars) {
Data_Frame <-
.data %>%
mutate(
across(!!.vars, ~ "Something"), # I was so close to this initially, I just missed the tilde.
) %>%
select({{.vars}}) %>%
as_tibble()
return(Data_Frame)
}
mtcars %>% Test_Function(vars)
#> # A tibble: 32 x 2
#> mpg cyl
#> <chr> <chr>
#> 1 Something Something
#> 2 Something Something
#> 3 Something Something
#> 4 Something Something
#> 5 Something Something
#> 6 Something Something
#> 7 Something Something
#> 8 Something Something
#> 9 Something Something
#> 10 Something Something
#> # ... with 22 more rows
由 reprex package (v2.0.1)
于 2021-08-12 创建现在@TimTeaFan 的建议:
library(dplyr, warn.conflicts = FALSE)
varlist <-
list(
"mpg" = "Something",
"cyl" = 2L
)
vars <- c("mpg", "cyl")
Test_Function <- function(.data, .varlist, .vars) {
Data_Frame <-
.data %>%
mutate(
!!! .varlist # I haven't really undstood the big-bang operator (!!!) before now, so this was a great demonstration!
) %>%
select(!!.vars) %>%
as_tibble()
return(Data_Frame)
}
mtcars %>% Test_Function(varlist, vars)
#> # A tibble: 32 x 2
#> mpg cyl
#> <chr> <int>
#> 1 Something 2
#> 2 Something 2
#> 3 Something 2
#> 4 Something 2
#> 5 Something 2
#> 6 Something 2
#> 7 Something 2
#> 8 Something 2
#> 9 Something 2
#> 10 Something 2
#> # ... with 22 more rows
由 reprex package (v2.0.1)
于 2021-08-12 创建如果您只想将标量分配给一个变量,那么您既不需要 across
也不需要函数来这样做。您可以只定义一个列表并在 dplyr::mutate
内使用三重爆炸运算符,或者更接近您的情况, dplyr::transmute
.
library(dplyr, warn.conflicts = FALSE)
vars <- list("mpg" = "something",
"cyl" = 2L)
mtcars <- head(mtcars)
mtcars %>%
transmute(!!! vars)
#> mpg cyl
#> Mazda RX4 something 2
#> Mazda RX4 Wag something 2
#> Datsun 710 something 2
#> Hornet 4 Drive something 2
#> Hornet Sportabout something 2
#> Valiant something 2
如果您想以类似于 across
的方式以编程方式创建新列,那么一个简单的 {tidyverse} 技巧是在 dplyr::mutate
中使用 purrr::map_dfc
。请注意,在下面的示例中,您可以根据其他列名使用任何其他函数甚至表达式:
library(purrr)
mtcars %>%
transmute(map_dfc(vars, ~ .x))
#> mpg cyl
#> Mazda RX4 something 2
#> Mazda RX4 Wag something 2
#> Datsun 710 something 2
#> Hornet 4 Drive something 2
#> Hornet Sportabout something 2
#> Valiant something 2
我在 github、{dplyover} 上也有一个包,它有一个函数 over
,它使用 dplyr::across
的语法循环创建类似于 purrr::map_dfc
。您可以使用 .names
参数即时创建列名。
library(dplyover) # https://github.com/TimTeaFan/dplyover
mtcars %>%
transmute(over(vars, ~ .x,
.names = "{x}_new"))
#> mpg_new cyl_new
#> Mazda RX4 something 2
#> Mazda RX4 Wag something 2
#> Datsun 710 something 2
#> Hornet 4 Drive something 2
#> Hornet Sportabout something 2
#> Valiant something 2
由 reprex package (v2.0.1)
于 2021-08-11 创建