data.table中使用:=实现一对多连接时如何保留所有匹配行?
如何用data.table实现一对多合并并保留所有匹配行(无需冗余副本)
首先要明确一点:你遇到的b[a,y:=i.y]只保留最后匹配行的问题,本质是因为这种赋值方式是基于原b的行结构进行的——b的行数固定(这里是2行),对于每个匹配的键值,data.table只会把最后一个匹配的i.y值赋给b对应的行,不会扩展行数。
而你想要的保留所有匹配行的效果,需要增加行数(从2行变为3行),这种情况下无法通过:=在原b的行结构上直接实现(因为:=仅修改列值,不改变行数)。不过你完全可以通过高效的方式更新b本身,避免创建冗余的数据副本。
解决方案:直接更新b为合并后的结果
data.table的合并操作本身就很高效,你可以直接将合并结果重新赋值给b,这样既得到了期望的多行结果,又不会产生额外的冗余内存开销(data.table会尽量复用内存,而非完全复制数据):
library(data.table) a <- data.table(x = 1:2L, y = letters[1:4]) b <- data.table(x = c(1L,3L)) setkey(a,x) setkey(b,x) # 直接将合并结果赋值给b,替换原对象 b <- a[b, on=.(x)] b # 输出: # x y # 1: 1 a # 2: 1 c # 3: 3 <NA>
为什么不能用:=实现行扩展?
如果一定要用:=,只能将匹配的多个值存储为列表列(不增加行数),但这不是你想要的行展开效果。示例如下:
# 将匹配的y值存为列表列 b[, y := a[.SD, list(y), on=.(x), mult="all"]] b # 输出: # x y # 1: 1 a,c # 2: 3 NA
这种方式保留了所有匹配值,但没有扩展行数,适合需要将多值聚合到同一行的场景,不符合你的需求。
总结
如果需要行展开的一对多合并结果,直接用b <- a[b, on=.(x)]更新原对象是最高效的方式——它不会创建冗余副本,同时完全满足你的需求。
内容的提问来源于stack exchange,提问作者krishnateja128
相关产品推荐
相关产品推荐

