使用与列名称相同的变量对数据表进行子集化

31

我想使用与列名称相同的变量对data.table进行子集处理,这会引起一些问题:

dt <- data.table(a=sample(c('a', 'b', 'c'), 20, replace=TRUE),
                 b=sample(c('a', 'b', 'c'), 20, replace=TRUE),
                 c=sample(20), key=c('a', 'b'))

evn <- environment()
a <- 'b'
dt[a == a]

#Expected Result
dt[a == 'b']

我看到了这个可能的解决方案:

env <- environment()
dt[a == get('a',env)]

但是它像这样不方便:

this.a = a
dt[a == this.a]

那么还有其他优雅的解决方案吗?


5
我们知道这个作用域问题。这是非常重要的,我们将尽快修复。感谢您的报告。目前,使用不同的变量名称是解决问题的方法。 - Arun
1
我有点困惑 - 你为什么认为 a == a 应该有效或是好的语法呢?目前我的 R-forge 似乎无法连接,所以我无法查看 @Arun 的链接和具体内容,但让 a == a 能够按照 OP 想要的方式工作,对我来说似乎是个坏主意,我认为你的最后一个解决方案才是正确的。 - eddi
1
除了我上面的评论之外,由于您的 data.table 已经按 a 键入,因此您可以执行 dt[a] - eddi
请查看以下链接:https://dev59.com/am7Xa4cB1Zd3GeqPvvfd#15102156 - mnel
2个回答

13

目前的临时解决方案可能是:

`..` <- function (..., .env = globalenv())
{
  get(deparse(substitute(...)), env = .env)
}

..(a)
## [1] "b"

dt[a==..(a)]
##    a b  c
## 1: b a 15
## 2: b a 11
## 3: b b  8
## 4: b b  4
## 5: b c  5
## 6: b c 12
尽管这看起来很优雅,但我仍在等待更加稳健的解决方案来解决这种作用域问题。 根据 @mnel 的建议编辑。
`..` <- function (..., .env = sys.parent(2))
{
  get(deparse(substitute(...)), env = .env)
}

3
env=sys.parent(2) 可能更安全。 - mnel
@mnel 很好的问题!我可以问一下“为什么”,以及在哪里可以找到相关的文档来阅读吗? - xb.
2
你可能正在从非全局环境调用 [.data.tablesys.parent(2) 将搜索并找到正确的调用环境。 - mnel
谢谢。sys.parent(2) 应该是一个更实用的选项! - xb.

10

现在很简单了(因为data.table中引入了..()语法):

dt[eval(dt[, a %in% ..a])]

如果你的情况更简单(因为 a 是第一列):

dt[eval(.(a))] # identical to dt["b"]

3
对于OP的字符串列的情况,dt [a]是一个好主意,但它并不适用于所有情况。例如,dt2 = data.table(x = c(1,2,2),key =“ x”); x = 2; dt2 [x],这里x被识别为一组行号向量。 - Frank 2
1
谢谢你的留言,Frank。你说得对。我已经将dt2[x]的方法替换为dt2[eval(.(x))]以实现泛化。 - George Shimanovsky

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