R: накопленная сумма с пропущенными датами

У меня есть два фрейма данных, один (фрейм данных 1) с датами и несколько наблюдений за каждой датой. В другой таблице (dataframe 2) у меня больше дат, чем в другом dataframe.

Я хотел бы рассчитать суммарную сумму по фрейму данных 1 и поместить результат в фрейм данных 2. Любая дата, которая существует в фрейме данных 2, но отсутствует в фрейме данных 1, должна просто иметь значение за предыдущий день.

Фрейм данных 1

Date        Obs  
2015-01-10  2  
2015-01-11  3  
2015-01-16  1  
2015-01-20  4  

Фрейм данных 2

Date       cumSum
2015-01-09  0
2015-01-10  2
2015-01-11  5
2015-01-12  5
2015-01-13  5
2015-01-14  5
2015-01-15  5
2015-01-16  6
2015-01-17  6
2015-01-18  6
2015-01-19  6
2015-01-20 10
2015-01-21 10

Пожалуйста, дайте мне знать, если что-то неясно. Любая помощь будет отличной!

Спасибо,

Майк

1 ответ

Решение

Мы могли бы использовать версию devel data.table т.е. v1.9.5 (Инструкции по установке версии devel here,

Мы преобразуем первый data.frame (df1) в data.table setDT(df1)), соединитесь со столбцом "Дата" в "df2", используя on опция (доступна в версии devel). Мы создаем столбец "Cumsum" на основе не-NA элементов в "Obs", выполняя кумулятивную сумму "Obs", указанную индексом строки в i (!is.na(Obs)). Затем мы можем использовать na.locf от library(zoo) заменить NA значения с предыдущими значениями, отличными от NA, и обновите столбец "Cumsum". Поскольку столбец "Obs" не находится в ожидаемом выводе, мы можем назначить (:=) это к NULL.

library(data.table)#v1.9.5+
library(zoo)
res <- setDT(df1)[df2['Date'], on='Date'][!is.na(Obs), Cumsum:=cumsum(Obs)
           ][, Cumsum:=na.locf(Cumsum, na.rm=FALSE)][, Obs := NULL]
res
#         Date Cumsum
# 1: 2015-01-09     NA
# 2: 2015-01-10      2
# 3: 2015-01-11      5
# 4: 2015-01-12      5
# 5: 2015-01-13      5
# 6: 2015-01-14      5
# 7: 2015-01-15      5
# 8: 2015-01-16      6
# 9: 2015-01-17      6
#10: 2015-01-18      6
#11: 2015-01-19      6
#12: 2015-01-20     10
#13: 2015-01-21     10

При необходимости мы можем заменить NA значение в 'Cumsum' с '0'

res[is.na(Cumsum), Cumsum:=0]

Или, как упоминал @Khashaa в комментариях, мы можем сделать это без na.locf используя roll=Inf

 setDT(df1)[,cumSum:=cumsum(Obs),][df2['Date'],
                       on='Date',roll=Inf][, Obs:= NULL][]

Или другой вариант match с na.locf чтобы получить числовой индекс и заменить не-NA индекс (из match) с накопленной суммой "Obs", используйте na.locf как и прежде, и при необходимости мы можем заменить NA с 0.

df2$Cumsum <- na.locf(cumsum(df1$Obs)[match(df2$Date, df1$Date)], na.rm=FALSE)

данные

df1 <- structure(list(Date = structure(c(16445, 16446, 16451, 16455),
class = "Date"), 
Obs = c(2L, 3L, 1L, 4L)), .Names = c("Date", "Obs"), 
row.names = c(NA, -4L), class = "data.frame")

df2 <-  structure(list(Date = structure(c(16444, 16445, 16446, 16447, 
16448, 16449, 16450, 16451, 16452, 16453, 16454, 16455, 16456
), class = "Date"), cumSum = c(0L, 2L, 5L, 5L, 5L, 5L, 5L, 6L, 
6L, 6L, 6L, 10L, 10L)), .Names = c("Date", "cumSum"), row.names = c(NA, 
-13L), class = "data.frame")
Другие вопросы по тегам