2016-03-29 2 views
4

Я пытаюсь объединить два кадра данных (df1 и df2).Совокупность одного кадра данных по временным интервалам из другого фрейма данных

Первый содержит 3 переменных: ID, Date1 и Date2.

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 переменные: ID, Date3 и Value.

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$Value, которые имеют один и тот же ID и для которых 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.table, plyr и dplyr, но не смогли найти решение.

+0

Вы можете использовать 'foverlaps' из' data.table' – akrun

+0

Возможный дубликат [Проверка даты между двумя датами в R] (http://stackoverflow.com/questions/31353595/checking-if-date-is -between-two-date-in-r) –

ответ

4

пар data.table решений, которые должны масштабироваться хорошо (и хорошим затычка, пока не-оборудования д объединений реализуется):

Do ком заготовки в J с использованием by=EACHI.

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

GREAT !!!! БЛАГОДАРИМ ВАС СМЫСЬ Символикс !!! Это именно то, что мне нужно !!! Хотя предлагаемые ранее методы занимали часы, с вашим решением потребовалось всего 28 секунд! Я просто не могу в это поверить! – EdM

+1

@ user3692906 - добро пожаловать. Эти объединения были для меня неоценимы! – SymbolixAU

+0

@ user3692906 - и «голос на голосование» всегда приветствуется ;-) – SymbolixAU

1

Вот основа R решение с использованием sapply():

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 
+0

Большое вам спасибо! Два решения - это больше, чем я ожидал. Они работают над набором тестовых данных, которые я сделал! У меня проблемы с памятью, чтобы запустить второе решение, и я жду, чтобы первый завершил работу ... более 1 часа! Слишком много данных! Есть ли у вас документация по использованию ri и функции (ri)? – EdM

3

С недавно внедренная non-equi присоединяется подвиг Юр в current development version из data.table, v1.9.7, это может быть сделано следующим образом:

dt2[dt1, .(sum = sum(Value)), on=.(ID, Date3>=Date1, Date3<=Date2), by=.EACHI] 
# ID  Date3  Date3 sum 
# 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 

Имен столбцов необходимо креплением .. будет работать на нем позже.

Смежные вопросы