如何在R中使用data.table进行基本的左外连接?

3

我有一个数据表格,其中包含列a和列b。我已将其分成两部分:below,其中b < .5,以及above,其中b > .5:

DT = data.table(a=as.integer(c(1,1,2,2,3,3)), b=c(0,0,0,1,1,1))
above = DT[DT$b > .5]
below = DT[DT$b < .5, list(a=a)]

我希望能够在abovebelow之间进行左外连接:对于above中的每个a,计算below中的行数。这等同于在SQL中执行以下操作:

with dt as (select 1 as a, 0 as b union select 1, 0 union select 2, 0 union select 2, 1 union select 3, 1 union select 3, 1),
  above as (select a, b from dt where b > .5),
  below as (select a, b from dt where b < .5)
select above.a, count(below.a) from above left outer join below on (above.a = below.a) group by above.a;
 a | count 
---+-------
 3 |     0
 2 |     1
(2 rows)

我该如何使用data.tables实现同样的功能?目前我尝试了以下方法:
> key(below) = 'a'
> below[above, list(count=length(b))]
     a count
[1,] 2     1
[2,] 3     1
[3,] 3     1
> below[above, list(count=length(b)), by=a]
Error in eval(expr, envir, enclos) : object 'b' not found
> below[, list(count=length(a)), by=a][above]
     a count b
[1,] 2     1 1
[2,] 3    NA 1
[3,] 3    NA 1

我需要更具体地说明一下,我已经尝试过使用merge,但这会消耗我的系统内存(而且数据集仅占据我的内存约20%)。


5
请用通俗易懂的语言描述你想要实现什么? - mbq
可能是[如何在R中合并数据框(内部,外部,左侧,右侧)?]的重复问题(https://dev59.com/1nM_5IYBdhLWcg3wn0lO) - Joris Meys
1
你本可以先尝试寻找答案。data.table是data.frame的扩展,并具有合并函数。 - Joris Meys
1
同意您应该用自然语言解释您想要的内容,但是除此之外,在版本1.6和(更新后的)1.6.4中我都遇到了一个错误:abs(j)中的错误:数学函数的非数字参数。 另外:警告消息: 在is.na(j)中:is.na()应用于类型为“NULL”的非(列表或向量)对象。 - IRTFM
抱歉,问题晚了 - 希望现在问题好了很多倍。 - Yang
4个回答

4

既然你正在使用data.table包:请查看?merge.data.table。虽然我没有使用过它,但它似乎可以实现你想要的功能:

merge(above, below, by="a", all.x=TRUE, all.y=FALSE)

事实上,合并是基本函数,也适用于数据框。 - mbq
3
merge.data.tablemerge.data.frame 实际上非常不同。 - IRTFM
@DWin 好的,但是尽管如此,我们并不需要使用 data.tables 来获得合并功能。 - mbq
4
@mbq. 是正确的... 但是如果正在使用 data.table 对象,则需要知道实现目标的正确语法,这只能从 ?merge.data.table 中获取,而不能从 ?merge.data.frame 中获取。 - IRTFM
如果按列是唯一有效的,则可以正常工作,但在左连接中并非总是如此。 - Hack-R

4

看看这个是否对您有所帮助。您的示例太简略,让我不知道您想要什么,但它似乎可能是above$a的值的制表,这些值也在below$a中。

table(above$a[above$a %in% below$a])

如果您还希望得到与上述相反的结果,即不在below中的值,则可以使用以下代码实现:
table(above$a[!above$a %in% below$a])

而且你可以将它们连接起来:

> c(table(above$a[above$a %in% below$a]),table(above$a[!above$a %in% below$a]) )
2 3 
1 2

通常情况下,table%in% 在运行时占用的空间较小且速度较快。

这个查询并没有返回计数为0的a,这就是我想要左外连接的原因。 - Yang
是的,它确实有作用。"零计数"来自于!x %in% y索引中的2个"3"。如果您想将它们标记为这样,可以在它们之间插入一个额外的命名值:zeros->=0, - IRTFM

2

我认为这更容易:

setkey(above,a)
setkey(below,a)

左外连接:

above[below, .N]

常规连接:

above[below, .N, nomatch=0]

带计数的全外连接:

merge(above,below, all=T)[,.N, by=a]

above[below, .N] 会不会因为 .N 而返回总行数? - gented

1

最终我找到了一种使用 data.table 的方法,我觉得这比 DWin 的 table 更符合我的理解方式,尽管可能因人而异:

result = below[, list(count=length(b)), by=a]
key(result) = 'a'
result = result[J(unique(above$a))]
result$count[is.na(result$count)] = 0

我不知道这是否可以更紧凑。我特别想能够做像result = below[J(unique(above$a)), list(count=length(b))]这样的事情,但那行不通。


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