【问题标题】:How can I merge two data frames with multiple common keys without duplicating rows in R?如何在不重复 R 中的行的情况下合并具有多个公共键的两个数据帧?
【发布时间】:2015-02-26 16:02:18
【问题描述】:

例如,假设我想合并 df1 和 df2(见下文)。它们不仅有不同的#s 行,而且还有不同的#s 列。它们还有多个重复的列,以及“销售”列下的重复值。我想做的是按“Sales”(不希望“Sales”下的重复值)和“Date”、“Price”和“SKU”(这些列下的重复值可以)合并,并且添加“PVC”列并填充任何缺失的单元格 w/NA 值。基本上,这是我想要的最终产品:

Date        Sales Price SKU   PVC
2007/01/02   1     1.29 52648 Q
2007/01/02   2     1.99 48721 N/A
2007/01/02   5     0.55 65897 N/A
2007/01/02   6     5.00 56482 N/A
2007/01/02   10    2.50 46521 N/A
2009/01/02   4     5.99 75677  Z

这样做:

merge(df1,df2,c("Date","Sales","Price","SKU"),all=TRUE)

不起作用,因为它消除了在所有 4 列上不完全匹配的任何行。尝试:

merge(df1,df2,by="Sales",all=TRUE)

不起作用,因为这会使“销售”下共享相同值的行重复。此外,我不希望在合并的数据框中看到像“日期”、“价格”和“SKU”这样的列重复出现(我以“Date.x”、“Date.y”、“价格”结束。 x”、“价格.y”、“SKU.x”、“SKU.y”)。

df1

Date        Sales Price SKU
2007/01/02   1     1.29 52648
2007/01/02   2     1.99 48721
2007/01/02   5     0.55 65897
2007/01/02   6     5.00 56482
2007/01/02   10    2.50 46521

df2

Date        Sales Price SKU   PVC
2007/01/02   1     3.29 52647  Q
2009/01/02   4     5.99 75677  Z    

【问题讨论】:

  • 能否再添加一个数据集:merge 的理想输出数据集。也就是说,您希望merge() 的输出是什么样的?
  • @Andrew Taylor,刚刚将其添加到顶部!谢谢!

标签: r merge duplicates


【解决方案1】:

这是一种使用data.table的方法:

require(data.table)
setkey(setDT(df1), Sales)
setkey(setDT(df2), Sales)

df1[df2, PVC := i.PVC]
rbind(df1, df2[!df1])

#          Date Sales Price   SKU PVC
# 1: 2007/01/02     1  1.29 52648   Q
# 2: 2007/01/02     2  1.99 48721  NA
# 3: 2007/01/02     5  0.55 65897  NA
# 4: 2007/01/02     6  5.00 56482  NA
# 5: 2007/01/02    10  2.50 46521  NA
# 6: 2009/01/02     4  5.99 75677   Z
  • setDTdata.frames 转换为 data.tables(不实际复制数据)。

  • setkey() 按两个data.tables上的Sales列对数据进行排序,并将这些列标记为关键列,我们将使用它来加入。

  • data.tables 中,连接的形式为 x[i],其中 xkeyed data.tablei 可能是也可能不是 keyed .它通过在x 中查找与i 中的每一行对应的匹配行来执行连接。

    因此df1[df2]df1 中查找与df2 中的每一行相对应的所有匹配行。唯一匹配的是Sales = 1。在那场比赛中,我们将一个新列PVC 分配给df1,其值来自df2PVC 列-使用i.PVC 表示(以区分当两个数据时我们引用哪个data.table .tables 具有相同的列名)。

  • 最后,我们执行 non-joinanti-join 以获取 df2 中所有不在 df1 中的行(一次再次匹配到键列Sales) 并简单地绑定得到最终结果。

HTH

【讨论】:

    【解决方案2】:

    使用library(dplyr)

    left_join(rbind(df1,df2[,-5]) %>% group_by(Sales) %>% slice(1), df2[,c(2,5)])
    

    这是一个解释,命令逐行分解。这样做,我使用了库 magrittr 来方便地使用 %<>% 运算符,它是 <-%>% 的组合

    df2_noPVC <- df2 %>% select(-PVC) ## pare down df2 so they can be row-bound
    bound <- rbind(df1,df2_noPVC) ## stack the dataframes
    bound %<>% group_by(Sales) %>% slice(1) ## take the first row for each sale #, removing duplicates
    result <- left_join(bound,df2[,c(2,5)]) ## now that you have the unique records, merge back the PVC field
    

    转折来自mergerbind 的组合。如果您想要来自 df2 而不是 df1 的 Sales = 1 记录,这将是一个更简单的问题,您可以只使用 rbindslice(重复数据删除)而不进行合并。

    【讨论】:

      【解决方案3】:

      base::mergedplyr 的混合。也绝对不是最漂亮的解决方案。我很想看到有人给出更好的解决方案,因为我确信只有merge 或简单的dplyr 参数字符串。

      df<- rbind(merge(df1,df2[,c(2,5)],by=c("Sales"),all.x=TRUE),df2) %>% 
        group_by(Sales) %>% 
        filter(row_number(desc(Sales)) == 1) %>% 
        arrange(Sales)
      
      
      
        Sales       Date Price   SKU PVC
      1     1 2007/01/02  1.29 52648   Q
      2     2 2007/01/02  1.99 48721  NA
      3     4 2009/01/02  5.99 75677   Z
      4     5 2007/01/02  0.55 65897  NA
      5     6 2007/01/02  5.00 56482  NA
      6    10 2007/01/02  2.50 46521  NA
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-18
        • 2020-05-27
        • 2020-10-15
        • 1970-01-01
        • 1970-01-01
        • 2021-12-23
        相关资源
        最近更新 更多