好的,所以我有两个不同的数据框(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
答案 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的重复等)。