是否有一种方法来更新现有的变量时,合并在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

这,虽然,创建两组相同的变量(即我最终有两个var1s和两个var2s)。我当然可以手动组合变量,但我不喜欢这样做,因为我的实际数据相当大(想想数百万的观察和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))

有没有人知道一种方法来重新合并这些观察和更新现有的变量,它们在主/x数据集中缺失,而不是在使用/y中缺失?在一个理想的世界里,我想要一些像update选项的Stata的merge,做到这一点。

如果我理解正确,OP希望找到df1$iddf2$id之间的匹配行。对于df1中没有找到匹配的行,第二次尝试应该在替代iddf1$id2df2$id之间找到匹配的行。此外,数据集非常大(包含数百万行),OP或多或少受限于base 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是否包含在返回id1

    df2$id
    [1] "a" "b" "c" NA  NA
    
  • 然后,我们检查df1$id2是否包含在df2$id中,id2返回为

    [1] NA  NA  NA  "d" "e"
    
  • 现在,我们可以合并id1id2,即,我们成对地选择第一个非na值,并替换df1中的id列,成为

    [1] "a" "b" "c" "d" "e"
    
  • df1中的id2列被删除,因为它不再需要。

  • 最后在id列上合并修改后的df1df2

Edit:data.tableapproach

正如OP所指出的,他的生产数据集由数百万个观察值和30-40个变量组成,可能值得考虑一个数据。表的方法。数据。表具有:=赋值运算符,允许通过引用快速更新列

使用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"]

通常mergedplyr::*_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

最新更新