【问题标题】:Merge data frames and overwrite values合并数据帧并覆盖值
【发布时间】:2013-04-09 04:09:06
【问题描述】:

如何合并 2 个相似的数据框,但有一个更重要?

例如:

数据框 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 填充空白

数据帧合并

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
}

【问题讨论】:

    标签: r merge


    【解决方案1】:

    这是一个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
    

    【讨论】:

    • 显示的输出缺少第四行:4 D 4
    • 小心,如果您的数据中已经有 x1 和 x1.y,那么您可能会得到意想不到的结果。
    【解决方案2】:

    使用 data.table 的 on= 参数的 v1.9.6 更新(允许 adhoc 连接

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

    这是data.table 解决方案。确保您的df1df2Date 列是具有所需水平的因子(用于订购)

    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
    

    【讨论】:

    【解决方案3】:
    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'。

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

    【讨论】:

    • 不错的答案,但代码中的更多 cmets 将使其非常有用。
    • 感谢您的回答,但很抱歉,我忘了提及一个重要信息,除了日期(键)列之外,我不知道表格中的其他列。有些可能匹配有些可能不匹配。我想我可以使用名称(dfrm1)和名称(dfrm2)之间的匹配来获取我需要将代码应用到的列? (当然,将 x 和 y 附加到 col 名称)
    • 感谢您的帮助,我接受了您的回答并对其进行了扩展,以涵盖未知类似列的情况。我已将解决方案添加到我的问题中,以便将来帮助任何人。
    • 谢谢。您可以考虑使用intersect 函数使“常用名称”的确定更加紧凑。 ComNams &lt;- intersect(names(df1), names(df2))
    【解决方案4】:

    考虑这个例子:

    > 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
    

    【讨论】:

    • 这很酷,但只有当您已经知道哪些列名将在两个数据帧中可用时才有效,OP 的问题并非如此(请参阅42-'s answer 上的澄清提交)。
    猜你喜欢
    • 1970-01-01
    • 2018-01-18
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 2022-01-14
    • 2019-03-24
    相关资源
    最近更新 更多