【问题标题】:Use merge() to update a data frame with values from a second data frame使用 merge() 使用第二个数据帧中的值更新数据帧
【发布时间】:2011-03-12 12:46:50
【问题描述】:

我正在尝试弄清楚如何使用merge() 来更新数据框。

以数据框foo为例

foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA))

具有以下值

index value
1     a   100
2     b   101
3     c    NA
4     d    NA

还有数据框bar

bar <- data.frame(index=c('c', 'd'), value=c(200, 201))

具有以下值:

 index value
1     c   200
2     d   201

当我运行以下 merge() 函数来更新 cd 的值时

merge(foo, bar, by='index', all=T)

结果如下:

 index value.x value.y
1     a     100      NA
2     b     101      NA
3     c      NA     200
4     d      NA     201

我希望merge() 的输出避免在此特定示例中创建value.xvalue.y 但只保留value 的原始列有没有一种简单的方法来做到这一点?

【问题讨论】:

  • 如果没有空值,结果应该是什么?
  • 你有没有得到这个问题的答案?我正在为同样的问题寻找解决方案。
  • 我也想知道为什么没有合并,比如说overwrite=TRUE 参数,当提供by 时会启动。每次想要重新运行合并时手动删除列是不合时宜的。
  • 我刚刚遇到了同样的问题,我认为对您的问题最直接的回答是@jangorecki 的回答,您应该在下面接受

标签: r join merge


【解决方案1】:

使用data.table的最优解

library(data.table)
setDT(foo)
setDT(bar)
foo[bar, on="index", value:=i.value]
foo
#   index value
#1:     a   100
#2:     b   101
#3:     c   200
#4:     d   201

[ data.table 方法中的第一个参数名为i,因此我们可以使用i. 前缀引用i 参数中的表中的列。

【讨论】:

  • 如果有多个列需要更新,比如 value1、value2 等,你会怎么做?
【解决方案2】:

我认为最简单的方法是在合并之前“标记”需要更新的值。

bar$update <- TRUE
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update"))
foo[!is.na(foo$update),]$value <- foo[!is.na(foo$update),]$value.update
foo$value.update <- NULL
foo$update <- NULL

使用'data.table'会更快

library(data.table)
foo <- as.data.table(foo)
bar <- as.data.table(bar)
bar[, update:=TRUE]
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update"))
foo[!is.na(update),value:=value.update]
foo[, c("value.update","update"):=NULL]
foo

   index value
1:     a   100
2:     b   101
3:     c   200
4:     d   201

【讨论】:

    【解决方案3】:

    另一种方法可能是:

    1. 从第一个数据帧中删除 NA

    2. 使用 rbind 追加数据,而不是使用合并:

    这是原始的两个数据框:

    foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA))
    bar <- data.frame(index=c('c', 'd'), value=c(200, 201))
    

    (1) 使用 is.na 的否定去除 NA:

    foo_new <- foo[!is.na(foo$value),]
    

    (2)绑定数据框,你会得到你要找的答案

    new_df <- rbind(foo_new,bar)
    
                new_df
                index value
                1     a   100
                2     b   101
                3     c   200
                4     d   201
    

    【讨论】:

      【解决方案4】:

      我还想介绍一个使用库 sqldf 和 R 集成 sqlite 数据库的 sql 解决方案。我喜欢 sql 的简单、准确和强大。
      准确性:因为我可以准确定义要更改的对象 = 行,而无需考虑 data.frame (foo.id = bar.id) 的顺序。
      权力:在 SET 和 WHERE 之后的 WHERE(第三行)我可以定义我想考虑更新的所有条件。
      简单:语法比在向量、矩阵或数据帧中使用索引更具可读性。

      library(sqldf)
      
      # I changed index to id since index does not work. 
      #   Obviously index is a key word in sqlite.
      
      (foo <- data.frame(id=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA)))
      (bar <- data.frame(id=c('c', 'd'), value=c(200, 201)))
      
      sqldf(c(paste("UPDATE foo"
                   ," SET value = (SELECT bar.value FROM bar WHERE foo.id = bar.id)"
                   ," WHERE value IS NULL"
                   )
              , " SELECT * FROM main.foo"
          )
      )
      

      这给了

        id value
      1  a   100
      2  b   101
      3  c   200
      4  d   201
      

      类似问题:
      r equivalent of sql update?
      R sqlite: update with two tables

      【讨论】:

      • SQL 语句可以跨多行运行,因此不需要paste
      【解决方案5】:

      merge() 不是总是将列绑定在一起吗? replace() 有效吗?

      foo$value <- replace(foo$value, foo$index %in% bar$index, bar$value)
      

      match() 所以顺序很重要

      foo$value[match(bar$index, foo$index)] <- bar$value
      

      【讨论】:

      • 使用replace() 的一个问题是如果bar 中的排序与foo 中的排序不同,它将无法正常工作。例如,如果您尝试在 bar &lt;- bar[c(2,1),] 之后运行上述示例,则最终结果不会正确。
      • 是的,match() 确实适用于我的示例。实际上,事实证明我的实际用例更复杂,我想在多个列之间进行匹配,而不仅仅是一个简单的向量。我认为 match() 在您想跨数据框的多个列进行匹配时不起作用。
      • 谢谢!使用 match() 的想法很好......但是,如果 bar 有另一个不包含在 foo 中的元素(我们想要更新并添加新的东西) bar
      • 如果您有多个索引列怎么办?
      【解决方案6】:

      merge() 只合并新数据。例如,如果您有几个城市的平均收入数据集,以及这些城市人口的单独数据集,您可以使用 merge() 将一组数据合并到另一组数据中。

      就像 apeescape 说的,replace() 可能就是你想要的。

      【讨论】:

        猜你喜欢
        • 2021-08-02
        • 2018-07-23
        • 1970-01-01
        • 1970-01-01
        • 2012-08-13
        • 1970-01-01
        • 1970-01-01
        • 2018-04-28
        相关资源
        最近更新 更多