如果我有data.table
> DT1 <- data.table(A=rep(c('A', 'B'), 3),
B=rep(c(1,2,3), 2),
val=rnorm(6), key='A,B')
> DT1
A B val
1: A 1 -1.6283314
2: B 2 0.5337604
3: A 3 0.9991301
4: B 1 1.1421400
5: A 2 0.1230095
6: B 3 0.4988504
我希望通过多个键进行子集,如下所示:
> DT1[J('A', 1)]
A B val
1: A 1 -0.004898047
但是,连接取决于键的顺序,因此键A的值必须始终排在第一位。即使您指定了名称(J()
或list()
),这也无效:
> DT1[J(1, 'A')]
Error in `[.data.table`(DT1, J(1, "A")) :
x.'A' is a character column being joined to i.'V1' which is type 'double'. Character columns must join to factor or character columns.
> DT1[J(B=1, A='A')]
Error in `[.data.table`(DT1, J(B = 1, A = "A")) :
x.'A' is a character column being joined to i.'B' which is type 'double'. Character columns must join to factor or character columns.
是否有一种语法可以在不知道密钥顺序的情况下按i
进行此类分组?
已添加:另一个用例是,如果我只想按B进行子集而不是按A进行子集 - 有没有办法在子集中跳过键?为J创建包装函数的当前答案似乎不允许这样做。
编辑:有些人提到过使用data.frame方式。我知道您可以使用逻辑值向量来进行子集化,但这对整个表的扫描速度很慢:
> DT1 <- data.table(A=rep(c(1,2,3), 100000), B=rep(c('A', 'B'), 150000), val=rnorm(300000), key='A,B')
> system.time(DT1[DT1$A==1, DT1$B=="A"])
user system elapsed
0.080 0.000 0.054
> system.time(DT1[J(1, 'A')])
user system elapsed
0.004 0.000 0.004
对相关讨论的一些参考:(1)
答案 0 :(得分:2)
怎么样......
myJ <- function(key,...) do.call(data.table,list(...))[,key,with=FALSE]
DT1[myJ(B=1,A='A',key=key(DT1))]
或
myJ1 <- function(...) myJ(key(DT1),...)
DT1[myJ1(B=1,A='A')]
这样,您必须正确标记项目。
答案 1 :(得分:2)
本着@Frank的答案,但试图自动获得密钥:
myJ2 = function(...) {
# 'x' a couple of frames above is where the original data.table sits
data.table(..., key = key(get('x', parent.frame(n = 3))))
}
DT1[myJ2(B=1, A='A')]
# A B val
#1: A 1 0.4328698