合并R

时间:2015-07-02 18:02:35

标签: r merge dataframe

好的,所以我有两个不同的数据框(df1和df2),为了简化它,它们有一个ID,一个日期和一个测试分数。在每个数据框中,人(ID)已经在多个日期进行了测试。当在两个数据帧之间查看时,一些人在df1中列出但在df2中没有,反之亦然,但是一些列在两者中并且它们可以以不同方式重叠。

我想将所有数据合并到一个框架中,但是棘手的部分是如果df1和df2中的任何ID和分数都在7天之内(我可以使用减去日期列来执行此操作),我想要结合那一行。

从本质上讲,对于每个ID,如果在7天内拍摄,则会有一行分别写入两个分数,如果不是,则会产生两个单独的行,一个来自df1,一个来自df2以及所有其他分数可能没有在两者中列出。

EX:

DF1

ID Date1(yyyymmdd) Score1
1  20140512        50
1  20140501        30
1  20140703        50
1  20140805        20
3  20140522        70
3  20140530        10

DF2

ID Date2(yyyymmdd) Score2
1  20140530        40
1  20140622        20
1  20140702        10
1  20140820        60
2  20140522        30
2  20140530        80

Wanted_df

ID Date1(yyyymmdd) Score1 Date2(yyyymmdd) Score2
1  20140512        50                     
1  20140501        30
1  20140703        50     20140702        10
1  20140805        20
1                         20140530        40
1                         20140622        20
1                         20140820        60
3  20140522        70
3  20140530        10
2                         20140522        30
2                         20140530        80

2 个答案:

答案 0 :(得分:1)

使用带有日期差异绝对值限制的外部联接。 (外连接 B保留A和B的所有行。)例如:

library(sqldf)
sqldf("select a.*, b.* from df1 a outer join df2 b on a.ID = b.ID and abs(a.Date1 - b.Date2) <=7")

请注意,您的日期变量必须是真实日期。如果它们当前是字符或整数,则需要执行类似df1$Date1 <- as.Date(as.character(df$Date1), format="%Y%M%D)等的操作。

答案 1 :(得分:1)

好的。我对伪造的外部联接答案感到不满(这可能在我不了解的库中是可能的,但有时候使用RDBMS也有优势......)所以这里有一个hacky解决方法。它假定所有连接最多只能一对一,你已经说过了。

# ensure the date columns are date type
df1$Date1 <- as.Date(as.character(df1$Date1), format="%Y%m%d")
df2$Date2 <- as.Date(as.character(df2$Date2), format="%Y%m%d")

# ensure the dfs are sorted 
df1 <- df1[order(df1$ID, df1$Date1),]
df2 <- df2[order(df2$ID, df2$Date2),]

# initialize the output df3, which starts as everything from df1 and NA from df2
df3 <- cbind(df1,Date2=NA, Score2=NA)

library(plyr) #for rbind.fill

for (j in 1:nrow(df2)){
  # see if there are any rows of test1 you could join test2 to
  join_rows <- which(df3[,"ID"]==df2[j,"ID"] & abs(df3[,"Date1"]-df2[j,"Date2"])<7 )
  # if so, join it to the first one (see discussion)
  if(length(join_rows)>0){
    df3[min(join_rows),"Date2"] <- df2[j,"Date2"]
    df3[min(join_rows),"Score2"] <- df2[j,"Score2"]
  } # if not, add a new row of just the test2
  else df3 <- rbind.fill(df3,df2[j,])
}
df3 <- df3[order(df3$ID,df3$Date1,df3$Date2),]
row.names(df3)<-NULL # i hate these
df3  
#    ID      Date1 Score1      Date2 Score2
# 1   1 2014-05-01     30       <NA>     NA
# 2   1 2014-05-12     50       <NA>     NA
# 3   1 2014-07-03     50 2014-07-02     10
# 4   1 2014-08-05     20       <NA>     NA
# 5   1       <NA>     NA 2014-05-30     40
# 6   1       <NA>     NA 2014-06-22     20
# 7   1       <NA>     NA 2014-08-20     60
# 8   2       <NA>     NA 2014-05-22     30
# 9   2       <NA>     NA 2014-05-30     80
# 10  3 2014-05-22     70       <NA>     NA
# 11  3 2014-05-30     10       <NA>     NA

我无法按照与您相同的排序顺序获取行,但它们看起来一样。

简短说明:对于df2中的每一行,看看df1中是否有一行你可以&#34;加入&#34;它来。如果没有,请将其粘在桌子的底部。在初始化和rbinding中,您将看到一些将空行或列分配为占位符的hacky方法。

为什么这是一个糟糕的hacky解决方法:对于大型数据集,将df3绑定到自身将消耗越来越多的内存。该循环绝对不是最优的,并且它的搜索没有利用表被排序的事实。如果有一次机会测试在一周内被两次拍摄,你会看到一些意想不到的行为(来自df2的重复等)。