如何在不重复R中的行的情况下将两个数据帧与多个公共密钥合并?

时间:2015-02-26 16:02:18

标签: r merge duplicates

例如,假设我要合并df1和df2(见下文)。它们不仅具有不同的行数,还具有不同的列数。它们还有多个重复的列,以及" Sales"重复自己的专栏。我想做的是合并"销售" (不要在"销售")和"日期","价格"和" SKU" (这些列下的重复值都可以),并添加" PVC"列和填充任何缺少的单元格与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)

不起作用,因为这会使" Sales"下的行共享相同的值。重复一遍。另外,我不想看到像" Date"," Price"和" SKU"等列。在合并的数据框中重复自己(我最后用" Date.x"," Date.y"," Price.x"," Price .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    

3 个答案:

答案 0 :(得分:2)

这是使用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
  • setDT data.frames 转换为 data.tables (无需实际复制数据)。

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

  • data.tables 中,联接的格式为x[i],其中x键控data.table 和{{ 1}}可以键入也可以不键入。它通过查找与i中每行对应的x中的匹配行来执行连接。

    因此,i会在df1[df2]中找到与df1中每一行对应的所有匹配行。唯一匹配的是df2。在该匹配项中,我们将新列Sales = 1分配给PVC,其值来自df1' df2列 - 使用PVC表示(以区分当data.tables具有相同列名时我们引用的data.table。)

  • 最后,我们执行非联接反联接以获取i.PVC中不在{{1}中的所有行(再次与键列df2匹配)并简单地绑定以获得最终结果。

HTH

答案 1 :(得分:1)

使用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(重复数据删除)合并。

答案 2 :(得分:0)

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