PAYATHON 2026

如何在 R 中使用 mutate 根据字符串表达式创建新列?

数据小陈

可以先将字符串解析成带名称的表达式列表,再通过 !!! 传给 mutate()。total、total2 会成为新列名,右侧表达式在数据集的列环境中计算。

可直接使用的写法

把字符串包装进 list(...) 后解析,再用 rlang::call_args() 提取参数。这个过程只解析调用,不执行 list(),因此表达式不会提前求值,名称也会保留下来。

library(tidyverse)

mutate_from_string <- function(.data, .formula) {
  parsed_call <- rlang::parse_expr(
    paste0("list(", .formula, ")")
  )
  expressions <- rlang::call_args(parsed_call)

  dplyr::mutate(.data, !!!expressions)
}

# 创建一列
my_formula1 <- "total = x + 1"

result1 <- mutate_from_string(diamonds, my_formula1)

# 同时创建两列
my_formula2 <- "total = x + y,total2 = y +z"

result2 <- mutate_from_string(diamonds, my_formula2)

查看相关列,确认计算结果:

result1 %>%
  select(x, total) %>%
  head()

result2 %>%
  select(x, y, z, total, total2) %>%
  head()

两个调用分别对应:

diamonds %>% mutate(total = x + 1)

diamonds %>% mutate(total = x + y, total2 = y + z)

为什么原来的写法有问题?

原示例中的变量名不一致:定义的是 my_formula1 和 my_formula2,调用时却使用了 my_f 和 my_f2。如果后两者没有提前定义,代码会因找不到对象而报错。

mutate(eval(str2lang(...))) 没有向 mutate() 提供具名参数。即使内部计算返回了向量,字符串里的 total = 也不会自动成为外层 mutate() 参数的名称。对于未命名的表达式,生成的列名可能来自表达式本身,因此会出现示例中描述的列名。

此外,下面的字符串不能直接作为一个完整的 R 表达式解析:

"total = x + y,total2 = y +z"

逗号需要位于函数调用等允许分隔参数的语法结构中。将它包装为 list(total = x + y, total2 = y + z) 后,解析器才能识别这两个具名参数。提取参数后,!!! 会将它们展开,传给 mutate()。

使用时需要注意什么?

不要用 strsplit(..., ",") 直接按逗号拆分。右侧的函数调用也可能包含逗号,例如:

my_formula3 <- "total = pmax(x, y), total2 = y + z"

result3 <- mutate_from_string(diamonds, my_formula3)

使用 R 的语法解析器可以保留 pmax(x, y) 内部的逗号。

字符串中的表达式必须符合 R 语法,引用的列也必须存在。这种写法会执行字符串中指定的 R 表达式,因此应只用于可信来源。如果字符串来自外部用户,还需要限制允许使用的列、运算符和函数。

备注:内容仅供参考。