R语言 通过保存在变量中的名称引用data.table列

vkc1a9a2  于 2023-05-20  发布在  其他
关注(0)|答案(5)|浏览(181)

data.table是一个很棒的R包,我正在开发的库中使用它。到目前为止,一切都很顺利,除了一个并发症。使用保存在变量中的名称引用data.table列似乎要困难得多(与传统的 Dataframe 相比)(例如,对于 Dataframe 将是: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"。使用distcolvalcol而不是distval执行上述操作的最佳方法是什么?

0yycz8jy

0yycz8jy1#

如果你要在j表达式中进行复杂的操作,你可能应该使用evalquote。在当前版本的data.table中,一个问题是eval的环境并不总是正确处理-eval and quote in data.table(注意:基于对软件包的更新,对该答案进行了更新。)-当前的修复方法是将.SD添加到eval。据我所知,从一些测试,我已经运行,这并不影响速度(的方式,例如。在j中具有.SD[1]将)。
有趣的是,这个问题只困扰j,你可以在i中正常使用eval(其中.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))]

请注意,我没有在一个eval(distcol)中添加.SD是可以的,但如果我将它从另一个eval中取出,就不会了。
另一种选择是使用get

diststr = "dist"
valstr = "val"

x[get(valstr) < 5, c(diststr) := get(diststr)*sum(get(diststr))]
hi3rlvi2

hi3rlvi22#

也许你已经知道这个解决方案了。

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]
mrwjdhj3

mrwjdhj33#

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

colname = as.name(x)

然后可以在subset函数中使用colname

1tu0hz3e

1tu0hz3e4#

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对复杂字符表达式非常敏感,通常不建议用于生产代码。

vnzz0bqm

vnzz0bqm5#

另一个简洁的解决方案是将列重命名为固定名称,在固定名称列上执行操作,然后重命名。避免所有不可读和不可记的代码。

setnames(dt, colname, "fixed_")
dt[,fixed_:=paste0("foo-",fixed_)]
setnames(dt, "fixed_", colname)

相关问题