按时间间隔从另一个数据帧聚合一个数据帧

时间:2016-03-29 12:22:59

标签: r data.table aggregate plyr data-manipulation

我试图聚合两个数据框(df1df2)。

第一个包含3个变量:IDDate1Date2

DF1

ID      Date1      Date2
 1 2016-03-01 2016-04-01
 1 2016-04-01 2016-05-01
 2 2016-03-14 2016-04-15
 2 2016-04-15 2016-05-17
 3 2016-05-01 2016-06-10
 3 2016-06-10 2016-07-15

第二个变量还包含3个变量:IDDate3Value

DF2

ID      Date3 Value
 1 2016-03-15     5
 1 2016-04-04     7
 1 2016-04-28     7
 2 2016-03-18     3
 2 2016-03-27     5
 2 2016-04-08     9
 2 2016-04-20     2
 3 2016-05-05     6
 3 2016-05-25     8
 3 2016-06-13     3

我们的想法是为每个df1行获取具有相同df2$ValueID介于Date3之间的Date1的总和和Date2

ID      Date1      Date2 SumValue
 1 2016-03-01 2016-04-01        5
 1 2016-04-01 2016-05-01       14
 2 2016-03-14 2016-04-15       17
 2 2016-04-15 2016-05-17        2
 3 2016-05-01 2016-06-10       14
 3 2016-06-10 2016-07-15        3

我知道如何对此进行循环,但数据框很大!有人有一个有效的解决方案吗?探索data.tableplyrdplyr但无法找到解决方案。

3 个答案:

答案 0 :(得分:4)

一些data.table解决方案应该可以很好地扩展(并且在实现非equi连接之前有良好的止损):

使用by=EACHI在J中进行比较。

library(data.table)
setDT(df1)
setDT(df2)

df1[, `:=`(Date1 = as.Date(Date1), Date2 = as.Date(Date2))]
df2[, Date3 := as.Date(Date3)]

df1[  df2,
      {
        idx = Date1 <= i.Date3 & i.Date3 <= Date2
        .(Date1 = Date1[idx],
          Date2 = Date2[idx],
          Date3 = i.Date3,
          Value = i.Value)
      }, 
      on=c("ID"),
      by=.EACHI][, .(sumValue = sum(Value)), by=.(ID, Date1, Date2)]

#   ID      Date1      Date2 sumValue
# 1:  1 2016-03-01 2016-04-01        5
# 2:  1 2016-04-01 2016-05-01       14
# 3:  2 2016-03-14 2016-04-15       17
# 4:  2 2016-04-15 2016-05-17        2
# 5:  3 2016-05-01 2016-06-10       14
# 6:  3 2016-06-10 2016-07-15        3

foverlap加入(如评论中所述)

library(data.table)
setDT(df1)
setDT(df2)

df1[, `:=`(Date1 = as.Date(Date1), Date2 = as.Date(Date2))]
df2[, Date3 := as.Date(Date3)]

df2[, Date4 := Date3]


setkey(df1, ID, Date1, Date2)


foverlaps(df2,
          df1,
          by.x=c("ID", "Date3", "Date4"),
          type="within")[, .(sumValue = sum(Value)), by=.(ID, Date1, Date2)]

#     ID      Date1      Date2 sumValue
# 1:  1 2016-03-01 2016-04-01        5
# 2:  1 2016-04-01 2016-05-01       14
# 3:  2 2016-03-14 2016-04-15       17
# 4:  2 2016-04-15 2016-05-17        2
# 5:  3 2016-05-01 2016-06-10       14
# 6:  3 2016-06-10 2016-07-15        3

进一步阅读

Rolling join on data.table with duplicate keys

foverlap joins in data.table

答案 1 :(得分:3)

最近在Authorization的{​​{3}}中实施了non-equi加入功能,可以按照以下方式完成:

data.table, v1.9.7

列名需要一些修复..以后会对它起作用。

答案 2 :(得分:1)

以下是使用sapply()的基本R解决方案:

df1 <- data.frame(ID=c(1L,1L,2L,2L,3L,3L),Date1=as.Date(c('2016-03-01','2016-04-01','2016-03-14','2016-04-15','2016-05-01','2016-06-01')),Date2=as.Date(c('2016-04-01','2016-05-01','2016-04-15','2016-05-17','2016-06-15','2016-07-15')));
df2 <- data.frame(ID=c(1L,1L,1L,2L,2L,2L,2L,3L,3L,3L),Date3=as.Date(c('2016-03-15','2016-04-04','2016-04-28','2016-03-18','2016-03-27','2016-04-08','2016-04-20','2016-05-05','2016-05-25','2016-06-13')),Value=c(5L,7L,7L,3L,5L,9L,2L,6L,8L,3L));
cbind(df1,SumValue=sapply(seq_len(nrow(df1)),function(ri) sum(df2$Value[df1$ID[ri]==df2$ID & df1$Date1[ri]<=df2$Date3 & df1$Date2[ri]>df2$Date3])));
##   ID      Date1      Date2 SumValue
## 1  1 2016-03-01 2016-04-01        5
## 2  1 2016-04-01 2016-05-01       14
## 3  2 2016-03-14 2016-04-15       17
## 4  2 2016-04-15 2016-05-17        2
## 5  3 2016-05-01 2016-06-15       17
## 6  3 2016-06-01 2016-07-15        3

请注意,在某些情况下,您的df1和预期输出的日期略有不同;我使用了df1个日期。

这是另一种尝试更加向量化的方法:将索引的笛卡尔积计算预先计算到两个帧中,然后使用索引向量执行单个向量化条件表达式以获得匹配的索引对,最后使用匹配的索引进行聚合期望的结果:

cbind(df1,SumValue=with(expand.grid(i1=seq_len(nrow(df1)),i2=seq_len(nrow(df2))),{
    x <- df1$ID[i1]==df2$ID[i2] & df1$Date1[i1]<=df2$Date3[i2] & df1$Date2[i1]>df2$Date3[i2];
    tapply(df2$Value[i2[x]],i1[x],sum);
}));
##   ID      Date1      Date2 SumValue
## 1  1 2016-03-01 2016-04-01        5
## 2  1 2016-04-01 2016-05-01       14
## 3  2 2016-03-14 2016-04-15       17
## 4  2 2016-04-15 2016-05-17        2
## 5  3 2016-05-01 2016-06-15       17
## 6  3 2016-06-01 2016-07-15        3