在 dplyr 的 mutate 中使用 across 的问题,其中要应用的函数取决于另一个 tibble
Problem using across in mutate in dplyr, where function to apply depends on another tibble
我正在尝试改变 tibble 的某些列,其中要使用的特定函数在另一个 tibble 中命名。设置代码如下,之后我解释问题。
library(tidyverse)
library(lubridate)
transforms <- list(
"floor_date" = function(x) {
floor_date(dmy(x), "month")
},
"integer" = function(x) {
as.integer(gsub("[^[:digit:]]", "", x))
}
)
data_meta <- tibble(
datafield = letters[1:3],
transform_to = c("floor_date", "", "integer")
)
# A tibble: 3 x 2
# datafield transform_to
# <chr> <chr>
# 1 a "floor_date"
# 2 b ""
# 3 c "integer"
data <- tibble(
a = c("09/09/2021", "19/09/2021", "06/10/2021"),
b = c("lorem", "ipsum", "dolor"),
c = c("99 bottles", "98 bottles", "97 bottles")
)
# A tibble: 3 x 3
# a b c
# <chr> <chr> <chr>
# 1 09/09/2021 lorem 99 bottles
# 2 19/09/2021 ipsum 98 bottles
# 3 06/10/2021 dolor 97 bottles
data_meta
tibble 包含 data
tibble 的每一列所需的转换函数(如果有)。这些转换函数位于命名列表 transforms
中。为了只关注那些需要转换的列,我定义了 needs_transform
:
needs_transform <- data_meta %>%
filter(nchar(transform_to) > 0)
# A tibble: 2 x 2
# datafield transform_to
# <chr> <chr>
# 1 a floor_date
# 2 c integer
我现在想使用 mutate(across(...))
来应用转换。我发现以下根据列名给出了正确的函数:
transforms[[(needs_transform %>% filter(datafield == "a") %>% select(transform_to))[[1,1]]]]
# function(x) {
# floor_date(dmy(x), "month")
# }
所以我尝试使用 cur_column()
函数进行以下正确过滤:
clean_data <- data %>%
mutate(across(
needs_transform$datafield,
~ transforms[[(needs_transform %>%
filter(datafield == cur_column()) %>% select(transform_to))[[1,1]]]]
))
# Error in `mutate()`:
# ! Problem while computing `..1 = across(...)`.
# Caused by error in `across()`:
# ! Problem while computing column `a`.
不幸的是,这不起作用,我不确定为什么,即使在检查回溯之后(可以提供它,但它没有帮助)。
我的第二次尝试是尝试将逻辑包装在一个函数中(注意 x
arg 什么都不做,但需要在 across
中使用):
get_transform <- function(x) {
t <- (needs_transform %>%
filter(datafield == cur_column()) %>%
select(transform_to))[[1,1]]
transforms[[t]]
}
clean_data <- data %>%
mutate(across(
needs_transform$datafield,
get_transform
))
# Error in `mutate()`:
# ! Problem while computing `..1 = across(needs_transform$datafield, get_transform)`.
# Caused by error in `across()`:
# ! Problem while computing column `a`.
几乎完全相同的错误消息。我在这里查看了几个线程,但没有什么与我想要做的完全匹配。任何人都可以帮助让它工作吗?或者这不是一个很好的方法,还有更好的方法吗?
实现您想要的结果的一个选项可能如下所示:
library(tidyverse)
library(lubridate)
trans <- function(x, y) {
fn_name <- data_meta %>%
filter(datafield == y) %>%
pull(transform_to)
transforms[[fn_name]](x)
}
data %>%
mutate(across(needs_transform$datafield, ~ trans(.x, cur_column())))
#> # A tibble: 3 × 3
#> a b c
#> <date> <chr> <int>
#> 1 2021-09-01 lorem 99
#> 2 2021-09-01 ipsum 98
#> 3 2021-10-01 dolor 97
您也可以试试:
data %>%
mutate( across(needs_transform$datafield,
~ transforms[[with(data_meta,
transform_to[datafield == cur_column()])]](.x)))
a b c
<date> <chr> <int>
1 2021-09-01 lorem 99
2 2021-09-01 ipsum 98
3 2021-10-01 dolor 97
或偶数:
data %>%
mutate( across(needs_transform$datafield,
~.x %>% {transforms %>%
getElement(data_meta %>%
filter(datafield == cur_column())%>%
pull(transform_to))}()))
我正在尝试改变 tibble 的某些列,其中要使用的特定函数在另一个 tibble 中命名。设置代码如下,之后我解释问题。
library(tidyverse)
library(lubridate)
transforms <- list(
"floor_date" = function(x) {
floor_date(dmy(x), "month")
},
"integer" = function(x) {
as.integer(gsub("[^[:digit:]]", "", x))
}
)
data_meta <- tibble(
datafield = letters[1:3],
transform_to = c("floor_date", "", "integer")
)
# A tibble: 3 x 2
# datafield transform_to
# <chr> <chr>
# 1 a "floor_date"
# 2 b ""
# 3 c "integer"
data <- tibble(
a = c("09/09/2021", "19/09/2021", "06/10/2021"),
b = c("lorem", "ipsum", "dolor"),
c = c("99 bottles", "98 bottles", "97 bottles")
)
# A tibble: 3 x 3
# a b c
# <chr> <chr> <chr>
# 1 09/09/2021 lorem 99 bottles
# 2 19/09/2021 ipsum 98 bottles
# 3 06/10/2021 dolor 97 bottles
data_meta
tibble 包含 data
tibble 的每一列所需的转换函数(如果有)。这些转换函数位于命名列表 transforms
中。为了只关注那些需要转换的列,我定义了 needs_transform
:
needs_transform <- data_meta %>%
filter(nchar(transform_to) > 0)
# A tibble: 2 x 2
# datafield transform_to
# <chr> <chr>
# 1 a floor_date
# 2 c integer
我现在想使用 mutate(across(...))
来应用转换。我发现以下根据列名给出了正确的函数:
transforms[[(needs_transform %>% filter(datafield == "a") %>% select(transform_to))[[1,1]]]]
# function(x) {
# floor_date(dmy(x), "month")
# }
所以我尝试使用 cur_column()
函数进行以下正确过滤:
clean_data <- data %>%
mutate(across(
needs_transform$datafield,
~ transforms[[(needs_transform %>%
filter(datafield == cur_column()) %>% select(transform_to))[[1,1]]]]
))
# Error in `mutate()`:
# ! Problem while computing `..1 = across(...)`.
# Caused by error in `across()`:
# ! Problem while computing column `a`.
不幸的是,这不起作用,我不确定为什么,即使在检查回溯之后(可以提供它,但它没有帮助)。
我的第二次尝试是尝试将逻辑包装在一个函数中(注意 x
arg 什么都不做,但需要在 across
中使用):
get_transform <- function(x) {
t <- (needs_transform %>%
filter(datafield == cur_column()) %>%
select(transform_to))[[1,1]]
transforms[[t]]
}
clean_data <- data %>%
mutate(across(
needs_transform$datafield,
get_transform
))
# Error in `mutate()`:
# ! Problem while computing `..1 = across(needs_transform$datafield, get_transform)`.
# Caused by error in `across()`:
# ! Problem while computing column `a`.
几乎完全相同的错误消息。我在这里查看了几个线程,但没有什么与我想要做的完全匹配。任何人都可以帮助让它工作吗?或者这不是一个很好的方法,还有更好的方法吗?
实现您想要的结果的一个选项可能如下所示:
library(tidyverse)
library(lubridate)
trans <- function(x, y) {
fn_name <- data_meta %>%
filter(datafield == y) %>%
pull(transform_to)
transforms[[fn_name]](x)
}
data %>%
mutate(across(needs_transform$datafield, ~ trans(.x, cur_column())))
#> # A tibble: 3 × 3
#> a b c
#> <date> <chr> <int>
#> 1 2021-09-01 lorem 99
#> 2 2021-09-01 ipsum 98
#> 3 2021-10-01 dolor 97
您也可以试试:
data %>%
mutate( across(needs_transform$datafield,
~ transforms[[with(data_meta,
transform_to[datafield == cur_column()])]](.x)))
a b c
<date> <chr> <int>
1 2021-09-01 lorem 99
2 2021-09-01 ipsum 98
3 2021-10-01 dolor 97
或偶数:
data %>%
mutate( across(needs_transform$datafield,
~.x %>% {transforms %>%
getElement(data_meta %>%
filter(datafield == cur_column())%>%
pull(transform_to))}()))