摘要:我希望将共享id
密钥的两个表合并为all=true
(完全外部联接),而不是将具有相同名称的列设置为{ {1}} var1.x
等,它们合并为一个列,其中左表中的缺失(NA)值由右表中的值填充(除了合并的标准行为,即,附加具有不同ID的行和具有不同名称的列)。
详细信息:
我想基于共享的var2.y
键列将table1
与table2
合并,以便:
1)如果id
和table1
具有相同名称的列(table2
除外),id
中的值将保留,如果它存在并替换为如果table1
中的值为NA,则table2
中的值。
2)如果table2具有table1没有(不同名称)的列,则它们将被合并(通过id)。
3)如果table1
的{{1}}与table1
中的id
不匹配,则table2
中不同名称列的值为NA
4)如果table2
的{{1}}与table2
中的id
不匹配,则会将其添加为新行,并将table1
中的不同列名称的值添加为table1
是NA。
3& 4与标准merge
一样all=TRUE
。
我担心我已经推翻了这个问题,因为我找不到一个直接的方法来执行merge
或join
并不涉及创建{{1}检查每一列。真实数据有大约1000列,因此对每个列进行ifelse
查找都是非常长的解决方案。
可重复的简化示例:
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
,var1
包含所有值,因此不会被忽略table1
中NA
的{{1}}被忽略(请注意,这并不包括下面描述的不同ID的行合并)。
对于专栏id3
,table2
缺少var2
索引的值,因此会从table
更新(请注意,这不是{\ n}}包括下面描述的不同ID的行合并。
对于列id3
,table2
中没有匹配列,因此保持原样。
对于列var3
,table2
中没有列var4
,因此var4
通过table1
键变量合并。< / p>
对于table2
中id
的行,id6
中没有匹配的table1
,因此列id6
的值仅为table2
var4
中table2
的行desired
的{{1}}输出为NA。
对于id6
中id8
的行,table2
中没有匹配的id8
,因此列table1
中的值只有var3
行table1
的{{1}}输出中的desired
为NA。
肯定有一种直接的方法可以使用id8
执行此操作吗?考虑到实际数据的大小,特别欢迎高效的解决方案。 data.table
软件包显然用于完成此操作,但它不再适用于CRAN,我无法通过zip从R3.2.3开始工作。是否有另一个包加紧完成这项任务?还有许多其他线程专注于为一个或几个具有已知名称的列解决此问题,但对于大量列,它们看起来并不实用。
答案 0 :(得分:10)
以这种方式:
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
创建和使用所有这些列名矢量非常麻烦。
关于原始问题......
以其他方式(不从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]
这样,所有步骤都可以通过引用修改table1
。
答案 1 :(得分:5)
这是另一个避免明确将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))]
我不知道哪个选项更快 - OP可以检查它。
答案 2 :(得分:3)
首先执行此操作以获取所有必需的行:
table1 <- table1[.(id = union(id, table2$id)), on = "id"]
我不喜欢mget
,所以我提出以下建议:
in_common <- parse(text=setdiff(intersect(names(table1), names(table2)), "id"))
for (ii in in_common)
table1[is.na(eval(ii)),
as.character(ii) :=
table2[.SD, eval(ii), on = "id"]]
新栏目很简单:
new_cols <- setdiff(names(table2), names(table1))
for (jj in new_cols)
table1[table2, (jj) := eval(parse(text = jj)), on = "id"]
我认为做这样的事情会更快:
in_common_c <- setdiff(intersect(names(table1), names(table2)), "id"))
in_common_q <- parse(text=in_common_c)
for (ii in seq_along(in_common_q))
table1[is.na(eval(in_common_q[ii])),
in_common_c[ii] :=
table2[.SD, eval(in_common_q[ii]), on = "id"]]
但我希望差异很小。