我对R很陌生。我正在尝试将一些列汇总到一个新列。因为只有聚合的列必须保存到DF,所以我使用transmute。
因为列名可能不同,所以我试图连接一些字符串以组成一段代码,然后使用parse和eval来处理此代码。
我放在一起的是:
transmute("aggr1" = as.numeric(val1) + as.numeric(val2), "aggr2" = as.numeric(val3) + as.numeric(val4))
如果我像这样制作一个新的数据框,它会完美地工作:
data_aggr <- df %>%
transmute("aggr1" = as.numeric(val1) + as.numeric(val2), "aggr2" = as.numeric(val3) + as.numeric(val4))
但是如果我放在一起的字符串看起来像:
composed = "transmute(\"aggr1\" = as.numeric(val1) + as.numeric(val2), \"aggr2\" = as.numeric(val3) + as.numeric(val4))"
然后我使用:
data_aggr <- df %>%
eval(parse(text=composed))
它不起作用。我收到错误:
error in mutate(.data, !!!dots)
我的解决方案是否可能。我做错了吗?
作为一般规则您几乎never想要在常规代码中使用parse
和eval
-实际上,它们的出现应警告您您正在错误地思考问题。这些是用于低级R编程的专用工具,分析代码中应该完全没有这些工具。
首先,在您的代码中,可能造成混淆的原因是在列名周围使用了双引号,因此您认为它们是字符串。实际上并非如此! R在多个位置静默接受字符串文字,而不是变量名,并且将它们作为变量名处理。
所以您的初始代码实际上等效于
transmute(aggr1 = as.numeric(val1) + as.numeric(val2), aggr2 = as.numeric(val3) + as.numeric(val4))
…不带引号,这种区别对于理解正在发生的事情至关重要。
现在,如何概括这一点,以便您实际上使用不同的列名(即计算值)?简而言之,您需要在列名前面使用!!
,并用:=
代替=
。
!!
导致dplyr将列名称解释为计算值,并且使用:=
而不是=
可以防止R将值视为函数调用参数名称(它可以解决R限制,因为!! x = y
为语法上无效)。
例如:
prefix = 'aggr'
data_aggr = df %>%
transmute(
!! paste0(prefix, 1) := as.numeric(val1) + as.numeric(val2),
!! paste0(prefix, 2) := as.numeric(val3) + as.numeric(val4)
)
显然如何计算列名取决于您的特定问题。
小插图programming with dplyr中介绍了如何动态调用dplyr函数的详细信息。
这提供了基于eval
和parse
的解决方案。正如@Konrad Rudolph指出的那样,强烈建议不要使用这种编程。
我认为
data_aggr <- df %>%
eval(parse(text=composed))
不是您要尝试做的。由于
df %>%
eval(parse(text=composed))
类似于
eval(df, parse(text=composed))
这不会创建您想要的输出。更改
composed <- "df %>% transmute(\"aggr1\" = as.numeric(val1) + as.numeric(val2), \"aggr2\" = as.numeric(val3) + as.numeric(val4))"
然后再次运行
data_aggr <- eval(parse(text=composed))
将为您提供预期的输出。