使用 merge() 使用第二个数据帧中的值更新数据帧

Posted

技术标签:

【中文标题】使用 merge() 使用第二个数据帧中的值更新数据帧【英文标题】:Use merge() to update a data frame with values from a second data frame 【发布时间】: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 时会启动。每次想要重新运行合并时手动删除列是不合时宜的。 另见:Replace missing values (NA) in one data set with values from another where columns match 我刚刚遇到了同样的问题,我认为对您的问题最直接的回答是@jangorecki 的回答,您应该在下面接受 【参考方案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】:

另一种方法可能是:

    从第一个数据帧中删除 NA

    使用 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() 可能就是你想要的。

【讨论】:

以上是关于使用 merge() 使用第二个数据帧中的值更新数据帧的主要内容,如果未能解决你的问题,请参考以下文章

合并第二个数据帧中只有一个额外列的数据帧[重复]

如果第一个数据帧中存在行,如何更新第二个数据帧的存在值

如果日期介于第二个数据帧中的两个日期之间,则 r 标记第一个数据帧中的行

将其他数据帧中的值获取到新数据帧的循环中

Spark SCALA - 连接两个数据帧,其中一个数据帧中的连接值位于第二个数据帧中的两个字段之间

如何根据 R 中的另一个数据帧解码一个数据帧中变量的值?