在R中合并data.table并保留原始顺序及添加匹配标识列
解决data.table合并保留行顺序并生成匹配标识列的问题
嘿,我来帮你搞定这个data.table合并的问题!你遇到的行顺序乱掉的情况,是因为merge()默认会按照连接键对结果排序,而咱们需要严格保留原dt的行顺序对吧?用data.table的按引用修改+左连接操作就能完美解决,还能顺便生成你要的match列。
完整解决方案代码
首先咱们先还原你的测试数据:
library(data.table) set.seed(100) dt <- data.table(g1=c("A", "B", "C", "D", "E", "F", "L", "O", "P", "J"), g2=c("G", "D", "C", "H", "K", "J", "L", "U", "I", "R"), value= rnorm(10)) ids <- data.table(labels=c("A", "B", "C", "D", "E", "F", "L", "O", "P", "J", "G", "H", "K", "U", "I", "R"), ids=c(1:16))
接下来直接在原dt上操作,全程保留原始行顺序:
# 1. 左连接ids表,给g1匹配对应的id,新增g1_id列 dt[ids, g1_id := i.ids, on = .(g1 = labels)] # 2. 同样给g2匹配对应的id,新增g2_id列 dt[ids, g2_id := i.ids, on = .(g2 = labels)] # 3. 生成match列:当g1和g2的label相同时标记为'T',否则'F' dt[, match := ifelse(g1 == g2, 'T', 'F')] # 查看最终结果 dt
结果说明
运行后你会得到完全符合预期的输出:
g1 g2 value g1_id g2_id match 1: A G -0.50219235 1 11 F 2: B D 0.13153117 2 4 F 3: C C -0.07891709 3 3 T 4: D H 0.88678481 4 12 F 5: E K 0.86014084 5 13 F 6: F J 1.09086728 6 10 F 7: L L 1.42053190 7 7 T 8: O U 0.93415334 8 14 F 9: P I 0.22375495 9 15 F 10: J R -0.35749574 10 16 F
为什么这个方法有效?
- 用
dt[ids, ..., on = .(g1 = labels)]这种左连接方式,会严格保留dt的原始行顺序——它只是把ids中匹配的值追加到dt对应的行上,不会改变行的排列顺序。 i.ids表示取ids表中的ids列值,直接赋值给dt的新列,全程是按引用修改,效率很高,适合大数据集。match列的生成逻辑:当g1和g2的label相同时,它们对应的ids必然相等,所以直接用g1 == g2判断就足够,当然你也可以写成ifelse(g1_id == g2_id, 'T', 'F'),结果完全一致。
补充:如果一定要用merge怎么办?
如果你坚持想用merge函数,记得设置sort=FALSE避免自动排序,之后还要按原dt的行顺序重新整理结果,不过这种方法相对繁琐:
# 第一次合并g1,关闭排序 test <- merge(dt, ids, by.x="g1", by.y="labels", sort=FALSE) # 第二次合并g2,关闭排序 test2 <- merge(test, ids, by.x="g2", by.y="labels", sort=FALSE) # 按原dt的行顺序重新排列结果 result <- test2[match(paste(dt$g1, dt$g2), paste(test2$g1, test2$g2))] # 添加match列 result[, match := ifelse(g1 == g2, 'T', 'F')]
不过显然第一种左连接的方法更简洁高效,推荐优先使用~
内容的提问来源于stack exchange,提问作者Connor Murray
相关产品推荐
相关产品推荐

