在 R 中合并时有没有办法更新现有变量?
Is there a way to update existing variables when merging in R?
我有两个数据集要在变量 id
上合并,其中一个有两个可能的 id,例如:
df1 <- data.frame(id = c('a', 'b', 'c', 'q', 'z'),
id2 = c('NA', 'g', 'NA', 'd', 'e'),
var1 = 1:5,
var3 = c('hi', 'hello', 'bonjour', 'howdy', 'hi'))
df2 <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var2 = 6:10,
var4 = 20:24)
我目前在主要链接变量上合并这些数据集:
merge1 <- merge(x = df1,
y = df2,
by = 'id',
all = TRUE)
我需要重新合并第一个数据框中那些具有第二个 ID 但在初始合并中不匹配的行,为此我将它们放在一个单独的数据框中,将它们从完全匹配数据集,然后合并两者:
df1.remerge <- merge1[which(!is.na(merge1$id2) &
is.na(merge1$var2)),]
df1.remerge$id <- df1.remerge$id2
merged <- merge1[which(is.na(merge1$id2) |
!is.na(merge1$var2)),]
merge2 <- merge(x = df1.remerge,
y = merged,
by = 'id',
all = TRUE,
suffixes = c('.m1', '.m2'))
# where .m1 = the remerged obs from df1 & .m2 = the original merged obs
不过,这会创建两组相同的变量(即我最终得到两个 var1
和两个 var2
)。我当然可以手动组合变量,但我不想这样做,因为我的实际数据非常大(考虑数百万个观察值和 30-40 个变量)并且这似乎效率很低。
最终我想要一个大致如下所示的数据集:
want.final <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var1 = 1:5,
var2 = 6:10,
var3 = c('hi', 'hello', 'bonjour', 'howdy', 'hi'),
var4 = 20:24)
但是我用这个方法得到的是这样的:
get.final <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var1.m1 = c('NA', 'NA', 'NA', 4, 5),
var1.m2 = c(1, 2, 3, 'NA', 'NA'),
var2.m1 = c('NA', 'NA', 'NA', 'NA', 'NA'),
var2.m2 = c(6, 7, 8, 9, 10),
var3.m1 = c('NA', 'NA', 'NA', 'howdy', 'hi'),
var3.m2 = c('hi', 'hello', 'bonjour', 'NA', 'NA'),
var4.m1 = c('NA', 'NA', 'NA', 'NA', 'NA'),
var4.m2 = c(20, 21, 22, 23, 24))
有谁知道重新合并这些观察结果并更新 master/x 数据集中缺失但 using/y 中未缺失的现有变量的方法?在一个理想的世界中,我想要像 Stata 的 merge
的 update
选项那样的东西。
一般来说,、merge
和 dplyr::*_join
将始终为您提供共享的 *.x
/*.y
变体-柱子; data.table
通常是相同的,但它的合并赋值操作可以帮助避开它。
基础 R
out <- merge(merge(df1, df2, by="id", all.x=TRUE), df2,
by.x="id2", by.y="id", all.x = TRUE, suffixes = c("", ".y"))
out$id[is.na(out$var2)] <- out$id2[is.na(out$var2)]
out$var2[is.na(out$var2)] <- out$var2.y[is.na(out$var2)]
out[,c("id2","var2.y")] <- NULL
out
# id var1 var2
# 1 d 4 9
# 2 e 5 10
# 3 b 2 7
# 4 a 1 6
# 5 c 3 8
data.table
重命名 df2$var2
在这里对于清晰和有条件的重新分配很有用。
library(data.table)
DT1 <- as.data.table(df1)
DT2 <- as.data.table(df2)
setnames(DT2, "var2", "var2new")
DT1[DT2, var2 := var2new, on = .(id)
][DT2, c("id", "var2") := .(id2, fifelse(is.na(var2), var2new, var2)), on = .(id2 == id)
][, id2 := NULL]
# id var1 var2
# <char> <int> <int>
# 1: a 1 6
# 2: b 2 7
# 3: c 3 8
# 4: d 4 9
# 5: e 5 10
如果我理解正确,OP 想要找到 df1$id
和 df2$id
之间的匹配行。对于 df1
中未找到匹配项的那些行,第二次尝试应该在备选 id df1$id2
和 df2$id
之间找到匹配行。此外,数据集非常大(包含数百万行)并且 OP 或多或少地受限于基本 R。
基础 R
因此,我们可以在df1
中先解决重复的id列,而不是对数百万行的数据集进行多次合并:
id1 <- df2$id[match(df1$id, df2$id)]
id2 <- df2$id[match(df1$id2, df2$id)]
df1$id <- ifelse(is.na(id1), id2, id1)
df1$id2 <- NULL
merge(df1, df2)
id var1 var3 var2 var4
1 a 1 hi 6 20
2 b 2 hello 7 21
3 c 3 bonjour 8 22
4 d 4 howdy 9 23
5 e 5 hi 10 24
说明
首先,我们检查 df1$id
是否包含在 df2$id
其中 returns id1
as
[1] "a" "b" "c" NA NA
然后,我们检查 df1$id2
是否包含在 df2$id
其中 returns id2
as
[1] NA NA NA "d" "e"
现在,我们可以 合并 id1
和 id2
,即,我们成对地选择第一个非 NA 值并将 df1
中的 id
列替换为
[1] "a" "b" "c" "d" "e"
df1
中的 id2
列已删除,因为不再需要它。
最后将修改后的df1
和df2
合并到id
列
编辑:data.table
方法
正如 OP 所指出的,他的生产数据集由 数百万个观察值和 30-40 个变量组成 可能值得考虑 data.table approach. data.table 具有 :=
允许通过引用快速更新列的赋值运算符.
使用data.table
,上述方法可以通过
实现
library(data.table)
setDT(df1)
setDT(df2)
df2[df1[, `:=`(id = fcoalesce(df2[df1, on = "id", x.id], df2[df1, on = "id==id2", x.id]),
id2 = NULL)], on = "id"]
我有两个数据集要在变量 id
上合并,其中一个有两个可能的 id,例如:
df1 <- data.frame(id = c('a', 'b', 'c', 'q', 'z'),
id2 = c('NA', 'g', 'NA', 'd', 'e'),
var1 = 1:5,
var3 = c('hi', 'hello', 'bonjour', 'howdy', 'hi'))
df2 <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var2 = 6:10,
var4 = 20:24)
我目前在主要链接变量上合并这些数据集:
merge1 <- merge(x = df1,
y = df2,
by = 'id',
all = TRUE)
我需要重新合并第一个数据框中那些具有第二个 ID 但在初始合并中不匹配的行,为此我将它们放在一个单独的数据框中,将它们从完全匹配数据集,然后合并两者:
df1.remerge <- merge1[which(!is.na(merge1$id2) &
is.na(merge1$var2)),]
df1.remerge$id <- df1.remerge$id2
merged <- merge1[which(is.na(merge1$id2) |
!is.na(merge1$var2)),]
merge2 <- merge(x = df1.remerge,
y = merged,
by = 'id',
all = TRUE,
suffixes = c('.m1', '.m2'))
# where .m1 = the remerged obs from df1 & .m2 = the original merged obs
不过,这会创建两组相同的变量(即我最终得到两个 var1
和两个 var2
)。我当然可以手动组合变量,但我不想这样做,因为我的实际数据非常大(考虑数百万个观察值和 30-40 个变量)并且这似乎效率很低。
最终我想要一个大致如下所示的数据集:
want.final <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var1 = 1:5,
var2 = 6:10,
var3 = c('hi', 'hello', 'bonjour', 'howdy', 'hi'),
var4 = 20:24)
但是我用这个方法得到的是这样的:
get.final <- data.frame(id = c('a', 'b', 'c', 'd', 'e'),
var1.m1 = c('NA', 'NA', 'NA', 4, 5),
var1.m2 = c(1, 2, 3, 'NA', 'NA'),
var2.m1 = c('NA', 'NA', 'NA', 'NA', 'NA'),
var2.m2 = c(6, 7, 8, 9, 10),
var3.m1 = c('NA', 'NA', 'NA', 'howdy', 'hi'),
var3.m2 = c('hi', 'hello', 'bonjour', 'NA', 'NA'),
var4.m1 = c('NA', 'NA', 'NA', 'NA', 'NA'),
var4.m2 = c(20, 21, 22, 23, 24))
有谁知道重新合并这些观察结果并更新 master/x 数据集中缺失但 using/y 中未缺失的现有变量的方法?在一个理想的世界中,我想要像 Stata 的 merge
的 update
选项那样的东西。
一般来说,、merge
和 dplyr::*_join
将始终为您提供共享的 *.x
/*.y
变体-柱子; data.table
通常是相同的,但它的合并赋值操作可以帮助避开它。
基础 R
out <- merge(merge(df1, df2, by="id", all.x=TRUE), df2,
by.x="id2", by.y="id", all.x = TRUE, suffixes = c("", ".y"))
out$id[is.na(out$var2)] <- out$id2[is.na(out$var2)]
out$var2[is.na(out$var2)] <- out$var2.y[is.na(out$var2)]
out[,c("id2","var2.y")] <- NULL
out
# id var1 var2
# 1 d 4 9
# 2 e 5 10
# 3 b 2 7
# 4 a 1 6
# 5 c 3 8
data.table
重命名 df2$var2
在这里对于清晰和有条件的重新分配很有用。
library(data.table)
DT1 <- as.data.table(df1)
DT2 <- as.data.table(df2)
setnames(DT2, "var2", "var2new")
DT1[DT2, var2 := var2new, on = .(id)
][DT2, c("id", "var2") := .(id2, fifelse(is.na(var2), var2new, var2)), on = .(id2 == id)
][, id2 := NULL]
# id var1 var2
# <char> <int> <int>
# 1: a 1 6
# 2: b 2 7
# 3: c 3 8
# 4: d 4 9
# 5: e 5 10
如果我理解正确,OP 想要找到 df1$id
和 df2$id
之间的匹配行。对于 df1
中未找到匹配项的那些行,第二次尝试应该在备选 id df1$id2
和 df2$id
之间找到匹配行。此外,数据集非常大(包含数百万行)并且 OP 或多或少地受限于基本 R。
基础 R
因此,我们可以在df1
中先解决重复的id列,而不是对数百万行的数据集进行多次合并:
id1 <- df2$id[match(df1$id, df2$id)]
id2 <- df2$id[match(df1$id2, df2$id)]
df1$id <- ifelse(is.na(id1), id2, id1)
df1$id2 <- NULL
merge(df1, df2)
id var1 var3 var2 var4 1 a 1 hi 6 20 2 b 2 hello 7 21 3 c 3 bonjour 8 22 4 d 4 howdy 9 23 5 e 5 hi 10 24
说明
首先,我们检查
df1$id
是否包含在df2$id
其中 returnsid1
as[1] "a" "b" "c" NA NA
然后,我们检查
df1$id2
是否包含在df2$id
其中 returnsid2
as[1] NA NA NA "d" "e"
现在,我们可以 合并
id1
和id2
,即,我们成对地选择第一个非 NA 值并将df1
中的id
列替换为[1] "a" "b" "c" "d" "e"
df1
中的id2
列已删除,因为不再需要它。最后将修改后的
df1
和df2
合并到id
列
编辑:data.table
方法
正如 OP 所指出的,他的生产数据集由 数百万个观察值和 30-40 个变量组成 可能值得考虑 data.table approach. data.table 具有 :=
允许通过引用快速更新列的赋值运算符.
使用data.table
,上述方法可以通过
library(data.table)
setDT(df1)
setDT(df2)
df2[df1[, `:=`(id = fcoalesce(df2[df1, on = "id", x.id], df2[df1, on = "id==id2", x.id]),
id2 = NULL)], on = "id"]