使用 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()
函数来更新 c
和 d
的值时
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.x
和value.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 <- bar[c(2,1),]
之后运行上述示例,则最终结果不会正确。
是的,match()
确实适用于我的示例。实际上,事实证明我的实际用例更复杂,我想在多个列之间进行匹配,而不仅仅是一个简单的向量。我认为 match()
在您想跨数据框的多个列进行匹配时不起作用。
谢谢!使用 match() 的想法很好......但是,如果 bar 有另一个不包含在 foo 中的元素(我们想要更新并添加新的东西) bar
如果您有多个索引列怎么办?【参考方案6】:
merge()
只合并新数据。例如,如果您有几个城市的平均收入数据集,以及这些城市人口的单独数据集,您可以使用 merge()
将一组数据合并到另一组数据中。
就像 apeescape 说的,replace()
可能就是你想要的。
【讨论】:
以上是关于使用 merge() 使用第二个数据帧中的值更新数据帧的主要内容,如果未能解决你的问题,请参考以下文章
如果日期介于第二个数据帧中的两个日期之间,则 r 标记第一个数据帧中的行