44

data.table是一个很棒的 R 包,我在我正在开发的库中使用它。到目前为止,一切进展顺利,除了一个并发症。使用保存在变量中的名称来引用列似乎要困难得多(与传统的数据框相比)data.table(对于数据框来说,例如:)colname="col"; df[df[,colname]<5,colname]=0

也许最让事情复杂化的是data.table. 在某些情况下,eval(colname)and get(colname),甚至c(colname)似乎有效。在其他情况下,DT[,colname, with=F]是解决方案。然而在其他方面,例如set()andsubset()函数,我根本没有找到解决方案。最后,前面讨论了一个极端的,虽然也是相当常见的用例(以编程方式将列名传递给 data.table),并且提出的解决方案,虽然显然在做他们的工作,但似乎不是特别可读......

也许我把事情复杂化了太多?如果有人能记下一份快速备忘单,以使用不同常见场景的变量来引用data.table列名,我将不胜感激。

更新:

如果我可以对列名进行硬编码,则可以使用一些具体示例:

x.short = subset(x, abs(dist)<=100)
set(x, which(x$val<10), "val", 0) 

现在假设distcol="dist"valcol="val"distcol使用andvalcol而不是distand来完成上述操作的最佳方法是什么val

4

4 回答 4

28

如果您要在j表达式中执行复杂的操作,您可能应该使用evaland quote。当前版本的一个问题data.table是环境eval并不总是被正确处理 - data.table 中的 eval 和 quote(注意:根据包的更新对该答案进行了更新。) - 和当前解决方法是添加.SDeval. 据我从一些测试中可以看出,我已经运行了这不会影响速度(例如拥有的方式.SD[1]j

有趣的是,这个问题只会困扰j你,你可以正常使用evali无论如何.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))]
于 2013-05-17T21:30:33.450 回答
11

也许您已经知道这个解决方案?

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]
于 2013-05-17T20:29:31.020 回答
4

假设您在变量中有列名x,您可以这样做

colname = as.name(x)

然后你可以colnamesubset函数中使用

于 2013-05-22T09:53:03.410 回答
1

eval绝对不推荐data.table使用动态保存的变量对 a 进行子集化的方法。以下示例将有所帮助:

# 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对复杂的字符表达式非常敏感,一般不推荐用于生产代码。

于 2019-08-26T13:37:14.523 回答