如何用data.table实现含可变列数的full join与update join结合
问题:结合全连接与更新连接动态处理data.table的可变列数
我需要将全连接和更新连接结合起来,处理列数可变的data.table场景,但未找到覆盖该场景的解决方案。核心需求是:
updateDT可新增行和任意数量的列updateDT中的数据优先级始终高于DT的现有数据
示例数据
初始数据表 DT
key_col value_col_1 value_col_2 <char> <int> <int> 1: a 1 11 2: b 2 12 3: c 3 13 4: d 4 14 5: e 5 15
更新数据表 updateDT
key_col value_col_1 value_col_2 value_col_3 <char> <int> <int> <int> 1: d 11 21 31 2: e 12 22 32 3: f 13 23 33 4: g 14 24 34
预期结果 resultDT
key_col value_col_1 value_col_2 value_col_3 <char> <int> <int> <int> 1: a 1 11 NA 2: b 2 12 NA 3: c 3 13 NA 4: d 11 21 31 5: e 12 22 32 6: f 13 23 33 7: g 14 24 34
硬编码实现(存在局限性)
我可以通过硬编码列名实现需求,但代码重复,且难以推广到动态处理updateDT中更多列的场景:
library(data.table) DT <- data.table(key_col = letters[1:5], value_col_1 = 1:5, value_col_2 = 11:15) updateDT <- data.table(key_col = letters[4:7], value_col_1 = 11:14, value_col_2 = 21:24, value_col_3 = 31:34) key_column <- "key_col" value_columns <- setdiff(c(names(DT), names(updateDT)), key_column) resultDT <- merge(DT, updateDT, by = "key_col", all = TRUE) resultDT[, value_col_1 := fifelse(is.na(value_col_1.y), yes = value_col_1.x, no = value_col_1.y)] resultDT[, value_col_2 := fifelse(is.na(value_col_2.y), yes = value_col_2.x, no = value_col_2.y)] resultDT[, c("value_col_1.x", "value_col_1.y", "value_col_2.x", "value_col_2.y") := NULL] print(resultDT)
编辑:基准测试结果(选用更快的方案)
接受ismirsehregal的答案,因其速度更快,以下是基准测试代码及结果:
library(microbenchmark) microbenchmark( ismirsehregal = { resultDT1 <- rbindlist(list(old = DT, new = updateDT), use.names = TRUE, fill = TRUE, idcol = "origin")[, key_count := .N, by = key_column] resultDT1 <- resultDT1[key_count == 1L | key_count > 1L & origin == 'new'][, c("key_count", "origin") := NULL] }, Wimpel = { DT[updateDT, on=.(key_col), (value_columns) := mget(paste0("i.", value_columns))] resultDT2 <- rbindlist(list(DT, updateDT[!key_col %in% DT$key_col,]), use.names = TRUE, fill = TRUE) }, times = 10L)
运行结果:
Unit: milliseconds expr min lq mean median uq max neval ismirsehregal 1.2166 1.2345 1.33790 1.2933 1.3531 1.8147 10 Wimpel 3.5286 3.5989 3.85624 3.7680 4.0916 4.5984 10
第二次编辑:updateDT不包含DT所有列的场景
当updateDT不包含DT的全部列时,原方案会出现问题:
library(data.table) DT <- data.table(key_col = letters[1:5], value_col_1 = 1:5, value_col_2 = 11:15) updateDT <- data.table(key_col = letters[4:7], value_col_2 = 11:14, value_col_3 = 21:24, value_col_4 = 31:34) key_column <- "key_col" # value_columns <- setdiff(c(names(DT), names(updateDT)), key_column) # Error: value for ‘i.value_col_1’ not found value_columns <- setdiff(intersect(names(DT), names(updateDT)), key_column) # does not insert all data from updateDT DT[updateDT, on=.(key_col), (value_columns) := mget(paste0("i.", value_columns))] rbindlist(list(DT, updateDT[!key_col %in% DT$key_col,]), use.names = TRUE, fill = TRUE)
内容的提问来源于stack exchange,提问作者ahnungslos
相关产品推荐
相关产品推荐

