总结自连接索引,同时避免R data.table中的笛卡尔积

时间:2015-02-27 09:39:56

标签: r data.table self-join cross-join

使用2列data.table,我想通过对第2列中共享元素的数量求和来总结第1列中的成对关系。换句话说,每个共享Y元素的数量是多少X值的成对组合具有?

例如,我可以通过两个步骤完成此操作,首先进行笛卡尔交叉连接,然后总结如下:

d = data.table(X=c(1,1,1,2,2,2,2,3,3,3,4,4), Y=c(1,2,3,1,2,3,4,1,5,6,4,5))
setkey(d, Y)
d2 = d[d, allow.cartesian=TRUE]
d2[, .N, by=c("X", "i.X")]
 #  X i.X N
 #1: 1   1 3
 #2: 2   1 3
 #3: 3   1 1
 #4: 1   2 3
 #5: 2   2 4
 #6: 3   2 1
 #7: 1   3 1
 #8: 2   3 1
 #9: 3   3 3
#10: 4   2 1
#11: 2   4 1
#12: 4   4 2
#13: 4   3 1
#14: 3   4 1

此结果的第二行表示X=1X=2共享3个Y值;而X=3只与X=4共享1个y值。

在绕过笛卡尔连接步骤时是否有任何方法可以做到这一点,从而导致表格效率低下?我希望在具有数百万行的表上执行类似的操作,并且笛卡尔连接将进入2^31向量大小限制(除了变慢)。

我想象这样的事情:

d[d, list(X, length(Y)), by=c("X", "i.X")]

但这会产生错误i.X not found

我可以使用下面的代码在SQL中执行此操作 - 但是无法弄清楚如何将其转换为data.table语法:

CREATE TABLE test (X integer, Y integer);
INSERT INTO test VALUES(1, 1);
INSERT INTO test VALUES(1, 2);
INSERT INTO test VALUES(1, 3);
INSERT INTO test VALUES(2, 1);
INSERT INTO test VALUES(2, 2);
INSERT INTO test VALUES(2, 3);
INSERT INTO test VALUES(2, 4);
INSERT INTO test VALUES(3, 1);
INSERT INTO test VALUES(3, 5);
INSERT INTO test VALUES(3, 6);
INSERT INTO test VALUES(4, 4);
INSERT INTO test VALUES(4, 5);

SELECT A.X, B.X, COUNT(A.Y) as N FROM test as A JOIN test as B WHERE A.Y==B.Y GROUP BY A.X, B.X;

关键是我想要总结的列与我加入的列相同。这个问题与这些问题类似,但并不完全相同:

R Data.Table Join on Conditionals

How to self join a data.table on a condition

关键的区别在于我想汇总索引列,这似乎与= .EACHI无关。

2 个答案:

答案 0 :(得分:4)

如果您可以将Y分成不具有X的大交集的群组,则可以按这些群组进行计算首先,产生一个较小的中间表:

d[, grp := Y <= 3] # this particular split works best for OP data
d[, .SD[.SD, allow = T][, .N, by = .(X, i.X)], by = grp][,
    .(N = sum(N)), by = .(X, i.X)]

上面的中间表只有16行,而不是26行。不幸的是,我无法想出一种自动创建此类分组的简单方法。

答案 1 :(得分:2)

您已经有用SQL编写的解决方案,因此我建议使用R包sqldf

这是代码:

library(sqldf)

result <- sqldf("SELECT A.X, B.X, COUNT(A.Y) as N FROM test as A JOIN test as B WHERE A.Y==B.Y GROUP BY A.X, B.X")