使用:= with eval(as.symbol())创建列

时间:2016-12-14 19:39:36

标签: r data.table

我正在使用data.table中的R(OS X 10.11.6上的版本3.3.2),并注意到从版本1.9.6到1.10.0的行为发生了变化使用:=运算符和名称的字符串。

我根据索引号重命名循环内的列。以前,我一直在eval(as.symbol("string"))的两边使用:=,但这不再适用(这是基于之前question的答案)。通过反复试验,我发现我需要在左侧使用("string"),在右侧使用eval(as.symbol("string"))

以下是演示此行为的MCVE

library(data.table)
dt <- data.table(col1 = 1:10, col2 = 11:20)

## the next lines would be inside a loop that is excluded to simplify this MCVE
colA = paste0("col", 1)
colB = paste0("col", 2)
colC = paste0("col", 3)

## Old code that worked with 1.9.6, but not longer works
dt[ , eval(as.symbol(colC)) := eval(as.symbol(colA)) + eval(as.symbol(colB))]

## New code that now works 1.10.0
dt[ , (colC) := eval(as.symbol(colA)) + eval(as.symbol(colB))]

我查看了data.table documentation并且无法弄清楚为什么这项工作有效。所以,这是我的问题:

为什么我需要右侧的eval(as.symbol("string")),而不是左侧?

1 个答案:

答案 0 :(得分:3)

discussion开始,现在假设如果j是单个字符串,则将其评估为符号,例如,dt[, "col" := 3]也可以。

当这成为默认设置时,确实有一些变化,但完整的故事包含在上一篇文章和data.table news中。

然而,您可能会感兴趣

new_cols = c("j1", "j2")
dt[, (new_cols) := value]  # brackets so we don't just make a new_col col

dt[, c("j1", "j2") := value]

您可以在不需要循环的情况下实现上述目标

library(data.table)

dt = data.table(a = c(2, 3), b = c(5, 7), c = c(11, 13))

cols1 = sapply(c("a", "b"), as.symbol)
cols2 = sapply(c("b", "c"), as.symbol)
new_cols = c("d", "e")

> print(dt)
   a b  c
1: 2 5 11
2: 3 7 13

dt[, (new_cols) := purrr::map2(cols1, cols2, ~ eval(.x) + eval(.y))]

   a b  c  d  e
1: 2 5 11  7 16
2: 3 7 13 10 20