如何在 dplyr::mutate 中使用 R 中的表达式
How to use an expression in dplyr::mutate in R
我想根据给定的字符向量添加一个新列。
例如,在下面的示例中,我想添加在 expr
:
中定义的列 d
library(magrittr)
data <- tibble::tibble(
a = c(1, 2),
b = c(3, 4)
)
expr <- "d = a + b"
如下:
data %>%
dplyr::mutate(d = a + b)
# # A tibble: 2 x 3
# a b d
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
但是,在下面的代码中,虽然计算本身(即添加)有效,但新列的名称与我预期的不同。
data %>%
dplyr::mutate(!!rlang::parse_expr(expr))
# # A tibble: 2 x 3
# a b `d = a + b`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
data %>%
dplyr::mutate(!!rlang::parse_quo(expr, env = rlang::global_env()))
# # A tibble: 2 x 3
# a b `d = a + b`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
data %>%
dplyr::mutate(rlang::eval_tidy(rlang::parse_expr(expr)))
# # A tibble: 2 x 3
# a b `rlang::eval_tidy(rlang::parse_expr(expr))`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
如何正确使用 dplyr::mutate 中的表达式?
我的问题类似于,但在我的示例中,新变量 (d
) 及其定义 (a + b
) 在单个字符向量 (expr
).
要为变异列获取所需的名称,您仍然可以使用相同的语法并将结果分配给具有首选名称的列。要获得此名称,您可以使用正则表达式查找 =
之前的内容,然后删除可能存在的任何前导或尾随空格。
expr <- "x = a * b"
col_name <- trimws(str_extract(expr,"[^=]+"))
data %>%
dplyr::mutate(!!col_name := !!rlang::parse_expr(expr))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
data %>%
dplyr::mutate(!!col_name := !!rlang::parse_quo(expr, env = rlang::global_env()))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
data %>%
dplyr::mutate(!!col_name := rlang::eval_tidy(rlang::parse_expr(expr)))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
让我们先看看dplyr::mutate
需要什么样的表达式来创建命名变量:我们需要一个包含表达式的命名列表,以根据给定列表元素名称的表达式创建变量。
library(tidyverse)
data <- tibble::tibble(
a = c(1, 2),
b = c(3, 4)
)
expr <- "d = a + b"
# let's rewrite the string above as named list containing an expression.
expr2 <- list(d = expr(a + b))
# this works as expected:
data %>%
mutate(!!! expr2)
#> # A tibble: 2 x 3
#> a b d
#> <dbl> <dbl> <dbl>
#> 1 1 3 4
#> 2 2 4 6
现在我们只需要一个函数将字符串转换为命名列表,其中包含等式 right-hand 边的表达式。该名称需要是等式的 left-hand 端。我们可以通过常规的字符串操作来做到这一点。最后,我们需要将等式的 right-hand 边从字符串转换为表达式。我们可以在这里使用基数 R 的 str2lang
。
create_expr_ls <- function(str_expr) {
expr_nm <- str_extract(str_expr, "^\w+")
expr_code <- str_replace_all(str_expr, "(^\w+\s?=\s?)(.*)", "\2")
set_names(list(str2lang(expr_code)), expr_nm)
}
expr3 <- create_expr_ls(expr)
data %>%
mutate(!!! expr3)
#> # A tibble: 2 x 3
#> a b d
#> <dbl> <dbl> <dbl>
#> 1 1 3 4
#> 2 2 4 6
由 reprex package (v0.3.0)
于 2022-01-23 创建
这些工作中的任何一个。第二个与第一个类似,但不要求 rlang
在搜索路径上。如果 d=
部分不存在于 expr
中,则第三个和第四个也有效,在这种情况下使用默认名称。最后一个只用了base R,也是最短的
data %>% mutate(within(., !!parse_expr(expr)))
data %>% mutate(within(., !!parse(text = expr)))
data %>% mutate(data, !!parse_expr(sprintf("tibble(%s)", expr)))
data %>% { eval_tidy(parse_expr(sprintf("mutate(., %s)", expr))) }
within(data, eval(parse(text = expr))) # base R
备注
假设这个前提:
library(dplyr)
library(rlang)
# input
data <- tibble(a = c(1, 2), b = c(3, 4))
expr <- "d = a + b"
我想根据给定的字符向量添加一个新列。
例如,在下面的示例中,我想添加在 expr
:
d
library(magrittr)
data <- tibble::tibble(
a = c(1, 2),
b = c(3, 4)
)
expr <- "d = a + b"
如下:
data %>%
dplyr::mutate(d = a + b)
# # A tibble: 2 x 3
# a b d
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
但是,在下面的代码中,虽然计算本身(即添加)有效,但新列的名称与我预期的不同。
data %>%
dplyr::mutate(!!rlang::parse_expr(expr))
# # A tibble: 2 x 3
# a b `d = a + b`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
data %>%
dplyr::mutate(!!rlang::parse_quo(expr, env = rlang::global_env()))
# # A tibble: 2 x 3
# a b `d = a + b`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
data %>%
dplyr::mutate(rlang::eval_tidy(rlang::parse_expr(expr)))
# # A tibble: 2 x 3
# a b `rlang::eval_tidy(rlang::parse_expr(expr))`
# <dbl> <dbl> <dbl>
# 1 1 3 4
# 2 2 4 6
如何正确使用 dplyr::mutate 中的表达式?
我的问题类似于d
) 及其定义 (a + b
) 在单个字符向量 (expr
).
要为变异列获取所需的名称,您仍然可以使用相同的语法并将结果分配给具有首选名称的列。要获得此名称,您可以使用正则表达式查找 =
之前的内容,然后删除可能存在的任何前导或尾随空格。
expr <- "x = a * b"
col_name <- trimws(str_extract(expr,"[^=]+"))
data %>%
dplyr::mutate(!!col_name := !!rlang::parse_expr(expr))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
data %>%
dplyr::mutate(!!col_name := !!rlang::parse_quo(expr, env = rlang::global_env()))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
data %>%
dplyr::mutate(!!col_name := rlang::eval_tidy(rlang::parse_expr(expr)))
# A tibble: 2 × 3
a b x
<dbl> <dbl> <dbl>
1 1 3 3
2 2 4 8
让我们先看看dplyr::mutate
需要什么样的表达式来创建命名变量:我们需要一个包含表达式的命名列表,以根据给定列表元素名称的表达式创建变量。
library(tidyverse)
data <- tibble::tibble(
a = c(1, 2),
b = c(3, 4)
)
expr <- "d = a + b"
# let's rewrite the string above as named list containing an expression.
expr2 <- list(d = expr(a + b))
# this works as expected:
data %>%
mutate(!!! expr2)
#> # A tibble: 2 x 3
#> a b d
#> <dbl> <dbl> <dbl>
#> 1 1 3 4
#> 2 2 4 6
现在我们只需要一个函数将字符串转换为命名列表,其中包含等式 right-hand 边的表达式。该名称需要是等式的 left-hand 端。我们可以通过常规的字符串操作来做到这一点。最后,我们需要将等式的 right-hand 边从字符串转换为表达式。我们可以在这里使用基数 R 的 str2lang
。
create_expr_ls <- function(str_expr) {
expr_nm <- str_extract(str_expr, "^\w+")
expr_code <- str_replace_all(str_expr, "(^\w+\s?=\s?)(.*)", "\2")
set_names(list(str2lang(expr_code)), expr_nm)
}
expr3 <- create_expr_ls(expr)
data %>%
mutate(!!! expr3)
#> # A tibble: 2 x 3
#> a b d
#> <dbl> <dbl> <dbl>
#> 1 1 3 4
#> 2 2 4 6
由 reprex package (v0.3.0)
于 2022-01-23 创建这些工作中的任何一个。第二个与第一个类似,但不要求 rlang
在搜索路径上。如果 d=
部分不存在于 expr
中,则第三个和第四个也有效,在这种情况下使用默认名称。最后一个只用了base R,也是最短的
data %>% mutate(within(., !!parse_expr(expr)))
data %>% mutate(within(., !!parse(text = expr)))
data %>% mutate(data, !!parse_expr(sprintf("tibble(%s)", expr)))
data %>% { eval_tidy(parse_expr(sprintf("mutate(., %s)", expr))) }
within(data, eval(parse(text = expr))) # base R
备注
假设这个前提:
library(dplyr)
library(rlang)
# input
data <- tibble(a = c(1, 2), b = c(3, 4))
expr <- "d = a + b"