Mek*_*lay 13 merge join r data.table
简介:我想通过共享id
密钥将两个表合并为all=true
(完全外部联接),而不是将具有相同名称的列设置为var1.x
var2.y
等,它们将合并为单个列,其中左表中缺少(NA)值由右表中的值填充(除了合并的标准行为,即附加具有不同ID的行和具有不同名称的列).
细节:
我想基于共享密钥列合并+更新table1
,以便:table2
id
1)如果table1
并且table2
具有相同名称(除了id
)之外的列,则如果值table1
存在,则保留为单独的值,table2
如果值为table1
NA ,则将值替换为值in .
2)如果table2具有table1没有(不同名称)的列,则它们被合并(通过id).
3)如果table1
具有id
不匹配的table2
,则不同名称列的值为table2
NA
4)如果table2
有一个id
不匹配的table1
,则将其添加为新行,并且不同列名的值为table1
NA.
3和4是与标准merge
带all=TRUE
.
我担心我已经推翻了这个问题,因为我无法找到一个简单的方法来执行此操作,merge
或者join
不涉及ifelse
在每个列上创建检查.真实数据有大约1000列,因此ifelse
对每个列进行查找都是非常长的解决方案.
可重复的简化示例:
table1 <- data.table(id =c("id1", "id2", "id3", "id4", "id5", "id6"),
var1=c(1,2,3,4,5, 6),
var2=c("a", "b", NA, "d", NA, "f"),
var3=c(NA, 12, 13, 14, 15, 16));
table2 <- data.table(id =c("id1", "id2", "id3", "id4", "id5", "id8"),
var1=c(1,2,NA,4,5, 8),
var2=c(NA, "b", "c", "d", "e", "h"),
var4=c("foo", "bar", "oof", "rab", NA, "sna"));
desired <- data.table(id=c("id1", "id2", "id3", "id4", "id5", "id6", "id8"),
var1=c(1,2,3,4,5, 6, 8),
var2=c("a", "b", "c", "d", "e", "f", "h"),
var3=c(NA, 12, 13, 14, 15, 16, NA),
var4=c("foo", "bar", "oof", "rab", NA, NA, "sna"));
table1;
id var1 var2 var3
1: id1 1 a NA
2: id2 2 b 12
3: id3 3 NA 13
4: id4 4 d 14
5: id5 5 e 15
6: id6 6 f 16
table2;
id var1 var2 var4
1: id1 1 a foo
2: id2 2 b bar
3: id3 NA c oof
4: id4 4 d rab
5: id5 5 e NA
6: id8 8 h sna
desired
id var1 var2 var3 var4
1: id1 1 a NA foo
2: id2 2 b 12 bar
3: id3 3 c 13 oof
4: id4 4 d 14 rab
5: id5 5 e 15 NA
6: id6 6 f 16 NA
7: id8 8 h NA sna
Run Code Online (Sandbox Code Playgroud)
期望输出的说明:
对于列var1
,table1
具有所有值,因此它被单独保留并且NA
for id3
in table2
被忽略(请注意,这不包括下面描述的不同ID的行合并).
对于列var2
,table
缺少索引的值id3
,因此更新自table2
(注意,这不包括下面描述的不同ID的行合并).
对于列var3
,没有匹配的列table2
,因此保持原样.
对于列var4
,没有列var4
在table1
,所以它是从合并table2
的id
关键变量.
对于带有id6
in的行,table1
没有匹配id6
in table2
,因此var4
仅在输出中的列的table2
值为NA .desired
id6
对于具有id8
in的行,table2
没有匹配id8
in table1
,因此var3
仅在列table1
的desired
输出中的列的值为NA id8
.
当然有一种直接的方法来做到这一点data.table
?考虑到实际数据的大小,特别欢迎高效的解决方案.该datamerge
程序包显然已经习惯了这一点,但它不再在CRAN上了,我无法让它在zip上运行R3.2.3.是否有另一个包加紧完成这项任务?还有许多其他线程专注于为具有已知名称的一个或几个列解决此问题,但对于大量列,它们似乎不实用.
Fra*_*ank 11
这是一种方式:
com.cols = setdiff(intersect(names(table1), names(table2)), "id")
com.cols.x = paste0(com.cols, ".x")
com.cols.y = paste0(com.cols, ".y")
# create combined table
DT = setkey(merge(table1, table2, by="id", all=TRUE), NULL)
# edit common columns where NAs are present
for (j in seq_along(com.cols))
DT[is.na(get(com.cols.x[j])), (com.cols.x[j]) := get(com.cols.y[j])]
# remove unneeded columns
DT[, (com.cols.y) := NULL]
# rename kept columns
setnames(DT, com.cols.x, com.cols)
identical(DT, desired) # TRUE
Run Code Online (Sandbox Code Playgroud)
创建和使用所有这些列名矢量相当混乱.
关于原来的问题......
这是另一种方式(没有从table2
原始帖子中导入新行):
com.cols = setdiff(intersect(names(table1), names(table2)), "id")
i.com.cols = paste0("i.", com.cols)
new.cols = c(i.com.cols, setdiff(names(table2), c("id", com.cols)))
# grab columns from table2
table1[table2, (new.cols) := mget(new.cols), on="id"]
# edit common columns where NAs are present
for (j in seq_along(com.cols))
table1[is.na(get(com.cols[j])), (com.cols[j]) := get(i.com.cols[j])]
# remove unneeded columns
table1[, (i.com.cols) := NULL]
Run Code Online (Sandbox Code Playgroud)
这样,所有步骤都是table1
通过引用的修改.
这是另一个避免将i.
列显式添加到原始表的选项:
com.cols = setdiff(intersect(names(table1), names(table2)), "id")
i.com.cols = paste0("i.", com.cols)
# I'm using the same var names as Frank, but new.cols is strictly the new ones here
new.cols = setdiff(names(table2), names(table1))
# this is easy - the previously absent cols
table1[table2, (new.cols) := mget(new.cols), on = 'id']
# now for the ones that need updating
table1[table2, on = 'id',
(com.cols) := Map(function(col, i.col) pmin(col, i.col, na.rm = T),
mget(com.cols), mget(i.com.cols))]
Run Code Online (Sandbox Code Playgroud)
我不知道哪个选项更快 - OP可以检查.