【问题标题】:Is there a way to update existing variables when merging in R?在 R 中合并时有没有办法更新现有变量?
【发布时间】:2021-11-01 00:12:12
【问题描述】:

我有两个要在变量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))

有没有人知道一种方法来重新合并这些观察结果并更新它们在 master/x 数据集中缺失而在 using/y 中没有缺失的现有变量?在一个理想的世界中,我想要像 Stata 的 mergeupdate 选项这样的东西。

【问题讨论】:

  • 预期输出是多少?如果您可以像 df1df2 那样使用 data.frame(..) 构建它,那将是理想的。谢谢!
  • 刚刚更新——如果还不清楚,请告诉我。
  • 即使有数百万行,它也总是只有两个变量,或者您是否需要一种编程方法,用两个以上的id* 变量重复这个过程?
  • 这只是两个id 变量,谢天谢地

标签: r dataframe data-structures merge


【解决方案1】:

如果我理解正确,OP 想要在 df1$iddf2$id 之间找到匹配的行。对于df1 中未找到匹配项的那些行,第二次尝试应在替代id df1$id2df2$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 是否包含在返回id1df2$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 列已被删除,因为它不再需要。

  • 最后将修改后的df1df2合并到id列上。

编辑:data.table 方法

正如 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"]

【讨论】:

    【解决方案2】:

    一般而言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
    

    数据表

    重命名 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
    

    【讨论】:

    • 感谢您的回答。我想我并没有像我应该做的那样清楚——我将有很多变量适用(不仅仅是我在这里展示的两个,更像是 40 左右),所以基本 R 选项可能是不理想,因此这个问题。不幸的是,我无权访问data.table 包(我正在使用受限访问数据,这意味着我只能使用预先批准的包)。如果您有更多想法,我将不胜感激,但还是要感谢您。
    • 我理解(并且刚刚意识到我从基本 R 块中省略了一个相当导入的行)。您正在寻找一种程序化的方式来做到这一点,对吗?如果可能的话,稍微填写样本数据以反映至少 1-2 列需要测试的列,这将非常有帮助。它总是只是一个双重合并步骤,还是迭代地合并各种类似df2的帧,直到所有字段都不是NA
    • 这只是双重合并,只是有更多的变量。我也错过了data.table;我之前检查时一定是拼错了,因为我们可以使用那个包。
    猜你喜欢
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    相关资源
    最近更新 更多