data.table
是一个很棒的R包,我在我正在开发的库中使用它。到目前为止,一切都很顺利,除了一个并发症。使用保存在变量中的名称来引用data.table
列似乎要困难得多(与传统数据帧相比)(对于数据帧,例如:colname="col"; df[df[,colname]<5,colname]=0
)。
也许最让事情变得复杂的是data.table
中明显缺乏语法一致性。在某些情况下,eval(colname)
和get(colname)
,甚至c(colname)
似乎都有效。在其他人中,DT[,colname, with=F]
是解决方案。然而在其他方面,例如set()
和subset()
函数,我根本没有找到解决方案。最后,一个极端的,虽然也很常见的用例在前面讨论过(passing column names to data.table programmatically),虽然显然做了他们自己的工作,所提出的解决方案似乎并不特别可读......
也许我太复杂了?如果有人可以记下快速备忘单,以便使用不同常见场景的变量来引用data.table
列名称,我将非常感激。
更新
提供的一些具体示例我可以对列名进行硬编码:
x.short = subset(x, abs(dist)<=100)
set(x, which(x$val<10), "val", 0)
现在假设distcol="dist"
,valcol="val"
。使用distcol
和valcol
而不是dist
和val
进行上述操作的最佳方法是什么?
答案 0 :(得分:22)
如果您要在j
表达式中执行复杂的操作,则应该使用eval
和quote
。当前版本的data.table
中存在的一个问题是,eval
的环境并不总是正确处理 - eval and quote in data.table(注意:根据对更新的更新,对该答案进行了更新包。) - 目前的修复方法是将.SD
添加到eval
。据我所知,一些测试表明我运行此操作不会影响速度(例如.SD[1]
中j
的方式。)
有趣的是,这个问题只会影响j
,您可以在eval
中使用i
,但.SD
无法使用{。}}。
另一个问题是分配,你必须有字符串。我知道一种从引用的表达式中提取字符串名称的方法 - 它不漂亮,但它有效。以下是将所有内容组合在一起的示例:
x = data.table(dist = c(1:10), val = c(1:10))
distcol = quote(dist)
valcol = quote(val)
x[eval(valcol) < 5,
capture.output(str(distcol, give.head = F)) := eval(distcol)*sum(eval(distcol, .SD))]
请注意我没有在.SD
中添加eval(distcol)
,但如果我将其从另一个eval
中删除则不会。
另一种选择是使用get
:
diststr = "dist"
valstr = "val"
x[get(valstr) < 5, c(diststr) := get(diststr)*sum(get(diststr))]
答案 1 :(得分:7)
也许您已经知道这个解决方案了吗?
DT[[colname]]
这是受@ eddi在以下评论中的解决方案的启发,使用OP的例子:
set.seed(1)
x = data.table(a = 1:10, b=rnorm(10))
colstr="b"
col <- eval(parse(text=paste("quote(",colstr,")",sep="")))
x[eval(col)<0]
x[eval(col)<0,c(colstr):=-100]
答案 2 :(得分:3)
假设您在变量x
中有列名,您可以
colname = as.name(x)
然后,您可以在colname
函数
subset
答案 3 :(得分:1)
eval
来使用动态保存的变量对data.table
进行子集化。以下示例将有所帮助:
# Toy data.table example
DT = data.table(a = c(1,2,3), b = c(4,5,6))
# Saved variable
mVar <- "a"
# Subset
DT[DT[[mVar]] < 2]
eval
对复杂的字符表达式非常敏感,通常不建议将其用于生产代码。