数据表中的动态列名

42

我正在尝试向data.table中添加动态列名的列。此外,我需要在添加这些列时使用by参数。例如:

test_dtb <- data.table(a = sample(1:100, 100), b = sample(1:100, 100), id = rep(1:10,10))
cn <- parse(text = "blah")
test_dtb[ , eval(cn) := mean(a), by = id]

# Error in `[.data.table`(test_dtb, , `:=`(eval(cn), mean(a)), by = id) : 
#  LHS of := must be a single column name when with=TRUE. When with=FALSE the LHS may be a vector of column names or positions.

另一个尝试:

cn <- "blah"
test_dtb[ , cn := mean(a), by = id, with = FALSE]
# Error in `[.data.table`(test_dtb, , `:=`(cn, mean(a)), by = id, with = FALSE) : 'with' must be TRUE when 'by' or 'keyby' is provided

Matthew更新:

这现在在R-Forge的v1.8.3上可行了。感谢您的关注!
有关新示例,请参见此类似问题:

使用data.table按组分配多列

3个回答

37

data.table 1.9.4 开始,你可以直接这样做:

## A parenthesized symbol, `(cn)`, gets evaluated to "blah" before `:=` is carried out
test_dtb[, (cn) := mean(a), by = id]
head(test_dtb, 4)
#     a  b id blah
# 1: 41 19  1 54.2
# 2:  4 99  2 50.0
# 3: 49 85  3 46.7
# 4: 61  4  4 57.1

请参阅?:=中的Details:

DT[i, (colvector) := val]

[...] 现在更喜欢使用此语法[...] 括号足以防止LHS成为符号;与c(colvector)相同


原始回答:

你的想法非常正确:构建一个表达式,在调用[.data.table时对其进行评估,这是执行此类操作的data.table方法。再往前一步,为什么不构造一个表达式,它将被评估为整个j参数(而不仅仅是其左手边)?

像这样的东西应该可以解决问题:

## Your code so far
library(data.table)
test_dtb <- data.table(a=sample(1:100, 100),b=sample(1:100, 100),id=rep(1:10,10))
cn <- "blah"

## One solution
expr <- parse(text = paste0(cn, ":=mean(a)"))
test_dtb[,eval(expr), by=id]

## Checking the result
head(test_dtb, 4)
#     a  b id blah
# 1: 30 26  1 38.4
# 2: 83 82  2 47.4
# 3: 47 66  3 39.5
# 4: 87 23  4 65.2

太棒了,谢谢。我本来以为我尝试过那个变化,但显然我没有。非常感谢您的帮助。 - Alex
+1 将此问题的链接添加到 FR#2120。似乎出现了很多次。 - Matt Dowle

17

可以使用bquote构建表达式。

cn <- "blah"
expr <- bquote(.(as.name(cn)):=mean(a))
test_dtb[,eval(expr), by=id]

1
比做“动态数据表格”好多了。 - Juancentro
很棒的答案,非常有用和灵活的方法。+1! - marbel

2
我相信setnames(DT, c(col.names))可以产生最易读的代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接