合并数据框并覆盖数值。

22

如何合并两个相似的数据框,但让其中一个更为重要?

例如:

数据框1

Date      Col1    Col2
jan         2      1
feb         4      2
march       6      3
april       8      NA

数据框2

Date      Col2    Col3
jan         9      10
feb         8      20
march       7      30
april       6      40

合并这些数据框,按日期排序,以数据框1为优先,并用数据框2填充空白处。

DataframeMerge

Date      Col1    Col2    Col3
jan         2       1      10
feb         4       2      20
march       6       3      30
april       8       6      40

编辑 - 解决方案

commonNames <- names(df1)[which(colnames(df1) %in% colnames(df2))]
commonNames <- commonNames[commonNames != "key"]
dfmerge<- merge(df1,df2,by="key",all=T)
for(i in commonNames){
  left <- paste(i, ".x", sep="")
  right <- paste(i, ".y", sep="")
  dfmerge[is.na(dfmerge[left]),left] <- dfmerge[is.na(dfmerge[left]),right]
  dfmerge[right]<- NULL
  colnames(dfmerge)[colnames(dfmerge) == left] <- i
}
4个回答

14
merdat <- merge(dfrm1,dfrm2, by="Date")  # seems self-documenting

#  explanation for next line in text below.
merdat$Col2.y[ is.na(merdat$Col2.y) ] <- merdat$Col2.x[ is.na(merdat$Col2.y) ]

只需将 'merdat$Col2.y' 重命名为 'merdat$Col2',然后删除 'merdat$Col2.x'。

回复要求更多评论:更新向量的部分内容的一种方法是构造一个逻辑向量进行索引,并使用“ [”将其应用于赋值的两侧。另一种方法是设计一个仅在赋值左侧具有逻辑向量的向量,然后使用 rep() 创建一个与 sum(logical.vector) 长度相同的向量。目标是使这两个实例的长度(和顺序)与要替换的项相同。


不错的答案,但在代码中再加上一些注释会使其更有用。 - Sam
感谢您的回答,但很抱歉我忘记提到一个非常重要的信息,除了日期(键)列之外,我不知道表中的其他列。有些可能匹配,有些可能不匹配。我想我可以使用名称(dfrm1)和名称(dfrm2)之间的匹配来获取我需要应用您的代码的列吗? (当然要将x和y附加到列名) - EvilWeebl
谢谢您的帮助,我采纳了您的答案并进行了扩展,以涵盖当相似的列是未知的情况。我已经将解决方案添加到我的问题中,以帮助未来的任何人。 - EvilWeebl
谢谢。您可以考虑使用intersect函数来更紧凑地确定“常见名称”。 ComNams <- intersect(names(df1), names(df2)) - IRTFM

12

使用data.table的v1.9.6版本更新on=参数(允许adhoc joins):

setDT(df1)[df2, `:=`(Col2 = ifelse(is.na(Col2), i.Col2, Col2), 
                     Col3 = i.Col3), on="Date"][]

这里是一个 data.table 的解决方案。请确保你的 df1df2 中的 Date 列是因子变量,并具有所需的级别(用于排序)。

require(data.table)
dt1 <- data.table(df1, key="Date")
dt2 <- data.table(df2, key="Date")
# Col2 refers to the Col2 of dt1 and i.col2 refers to that of dt2
dt1[dt2, `:=`(Col3 = Col3, Col1 = Col1, 
        Col2 = ifelse(is.na(Col2), i.Col2, Col2))]

# the result is stored in dt1
> dt1
#     Date Col1 Col2 Col3
# 1:   jan    2    1   10
# 2:   feb    4    2   20
# 3: march    6    3   30
# 4: april    8    6   40

data.table有一个函数可以在多个列中提取非空值,请参见:https://rdrr.io/cran/data.table/man/coalesce.html - Feng Jiang

9
这里有一个 dplyr 解决方案。感谢 @docendo discimus。
df1 <- data.frame(y = c("A", "B", "C", "D"), x1 = c(1,2,NA, 4)) 

  y x1
1 A  1
2 B  2
3 C NA
4 D  4

df2 <- data.frame(y = c("A", "B", "C"), x1 = c(5, 6, 7))

  y x1
1 A  5
2 B  6
3 C  7

dplyr

left_join(df1, df2, by="y") %>% 
transmute(y, x1 = ifelse(is.na(x1.y), x1.x, x1.y))

  y x1
1 A  5
2 B  6
3 C  7

2
显示的输出缺少第四行:4 D 4 - ChrisW
1
注意,如果您的数据中已经有 x1 和 x1.y,则可能会出现意外结果。 - Saren Tasciyan

5
考虑这个例子:
> d1 <- data.frame(x=1:4, a=2:5, b=c(3,4,5,NA))
> d1
  x a  b
1 1 2  3
2 2 3  4
3 3 4  5
4 4 5 NA
> d2 <- data.frame(x=1:4, b=c(6,7,8,9), c=11:14)
> d2
  x b  c
1 1 6 11
2 2 7 12
3 3 8 13
4 4 9 14

现在使用mergewithin,以及ifelse
> within(merge(d1, d2, by="x"), {b <- ifelse(is.na(b.x),b.y,b.x); b.x <- NULL; b.y <- NULL})
  x a  c b
1 1 2 11 3
2 2 3 12 4
3 3 4 13 5
4 4 5 14 9

2
这很酷,但它只适用于您已经知道哪些列名将在两个数据框中可用的情况下,而这不是 OP 问题的情况(请参见 42-'s answer 上的澄清提交)。 - naught101

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接