如何在R中使用setDT连接表并合并多匹配的id2值
问题描述
现有两个数据表table1和table2,数据定义如下:
library(data.table) table1 <- data.frame(id1 = c(1324, 7822, 2324, 29, 9999, 1010), class = c(1, 1, 1, 2, 2, 1), type = c("A", "A", "A", "B", "C", "D"), number = c(1, 2.5, 98, 100, 80, 50)) table2 <- data.frame(id2 = c(1992, 1987, 1998, 1998, 2000, 2000, 2000, 2010, 2012), class = c(3, 3, 1, 1, 3, 1, 2, 5, 1), type = c("B", "C", "D", "A", "D", "D", "C", "B", "A"), min_number = c(0, 0, 34, 0, 20, 45, 5, 23, 1), max_number = c(18, 18, 50, 100, 100, 100, 100, 9, 10))
数据表内容:
> table1 id1 class type number 1 1324 1 A 1.0 2 7822 1 A 2.5 3 2324 1 A 98.0 4 29 2 B 100.0 5 9999 2 C 80.0 6 1010 1 D 50.0 > table2 id2 class type min_number max_number 1 1992 3 B 0 18 2 1987 3 C 0 18 3 1998 1 D 34 50 4 1998 1 A 0 100 5 2000 3 D 20 100 6 2000 1 D 45 100 7 2000 2 C 5 100 8 2010 5 B 23 9 9 2012 1 A 1 10
需要基于class和type字段连接两个表,将table2中匹配的id2字段合并到table1中,存储为final_tab1_tab2。当前使用的代码仅保留了最后一个匹配的id2值:
tab1_tab2 <- setDT(table1)[setDT(table2), on = c("class", "type"), id2 := id2]
输出结果:
> tab1_tab2 id1 class type number id2 1: 1324 1 A 1.0 2012 2: 7822 1 A 2.5 2012 3: 2324 1 A 98.0 2012 4: 29 2 B 100.0 NA 5: 9999 2 C 80.0 2000 6: 1010 1 D 50.0 2000
期望输出是将所有匹配的id2用;分隔,格式如下:
> final_tab1_tab2 id1 class type number id2 1: 1324 1 A 1.0 1998;2012 2: 7822 1 A 2.5 1998;2012 3: 2324 1 A 98.0 1998;2012 4: 29 2 B 100.0 NA 5: 9999 2 C 80.0 2000 6: 1010 1 D 50.0 1998;2000
要求高效处理数千行数据,避免使用for循环。
解决方案
利用data.table的分组聚合和左连接功能即可实现,全程基于向量化操作,无需循环:
- 先对
table2按class和type分组,将每组的id2用;拼接成字符串:
table2_agg <- setDT(table2)[, .(id2_str = paste(id2, collapse = ";")), by = .(class, type)]
- 将聚合后的表与
table1进行左连接,把拼接好的id2_str字段合并到原表:
final_tab1_tab2 <- setDT(table1)[table2_agg, on = c("class", "type"), id2 := id2_str]
执行后得到的结果完全符合期望:
> final_tab1_tab2 id1 class type number id2 1: 1324 1 A 1.0 1998;2012 2: 7822 1 A 2.5 1998;2012 3: 2324 1 A 98.0 1998;2012 4: 29 2 B 100.0 NA 5: 9999 2 C 80.0 2000 6: 1010 1 D 50.0 1998;2000
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

