仅给定日期向量,扩展(不相等的)日期点之间的数据

Given only vector of dates, expand data in between (unequal) date points

其他问题围绕着开始和结束日期。 (请参阅以下示例 Expand rows by date range using start and end date

我的问题有所不同,因为我只有一个日期列,我想将不相等的日期范围转换为每日计数。这个特定的例子创建了一次处理工作现场的工人数量。不同剧组的人来的日期不同

提供的简要数据框如下:

dd <- data.frame(date=as.Date(c("1999-03-22","1999-03-29","1999-04-08")),work=c(43,95,92),cumwork=c(43,138,230))

我希望数据看起来像这样:

dw <- data.frame(date=c(seq(as.Date("1999-03-22"),as.Date("1999-04-10"),by= "day")),
       work=c(rep(43,7),rep(95,10),rep(92,3)),
       cumwork=c(rep(43,7),rep(138,10),rep(230,3)))

我已经坚持了一段时间。如有任何帮助,我们将不胜感激!

更新(7/5/2017):正如@Scarabee 所指出的,数据框中的日期 'dd' 应该是日期格式。已更新代码以反映这一点

一种可能的方式:

首先,将您感兴趣的日期序列创建为单列数据框:

v <- data.frame(date = seq(min(dd$date), as.Date("1999-04-10"), by="day"))

接下来,加入您的原始数据框并填充缺失值,例如使用 dplyrzoo:

library(dplyr)
library(zoo)

v %>% 
  left_join(dd, by = "date") %>% 
  na.locf

NB:我想你的数据框 dd 实际上包含日期(而不是因素)。

dd <- data.frame(date=as.Date(c("1999-03-22","1999-03-29","1999-04-08")),work=c(43,95,92),cumwork=c(43,138,230))

类似的解决方案,使用基础 R(和 zoo 包):

dd$date <- as.Date(as.character(dd$date))
my.seq <- data.frame(date=seq.Date(from=range(dd$date)[1], to=range(dd$date)[2], by="day"))
output <- merge(my.seq, dd, all.x=TRUE)
output <- zoo::na.locf(output)

您首先必须将日期转换为日期格式。然后单独创建一个完整日期的向量并将其与原始数据合并。最终,运行 一个 "last observation carried forward" 算法。

这是一个非常快速的纯基础 R 解决方案:

ExpandDates <- function(df, lastColRepeat) {
    myDiff <- diff(df$date)
    dfOut <- data.frame(df$date[1] + 0:(sum(myDiff) + lastColRepeat - 1L),
                     stringsAsFactors=FALSE)
    myDiff <- c(myDiff, lastColRepeat)
    for (i in 2:3) {dfOut[,i] <- rep(df[ ,i], times = myDiff)}
    names(dfOut) <- names(df)
    dfOut
}

最后一个参数是确定最后一个值应该重复的次数。就目前而言,原始 data.frame 中没有任何内容可以提供此值。我还假设 "date" 字段实际上是@Scarabee 指出的日期。

这里是一些测试数据:

set.seed(123)
workVec <- sample(5000, 3000)
testDF <- data.frame(date = as.Date(sort(sample(12000, 3000)), 
                                    origin = "1970-01-01"), work = workVec, 
                                                    cumwork = cumsum(workVec))

DplyrTest <- function(dd) {  ## from @Scarabee
    v <- data.frame(date = seq(min(dd$date), max(dd$date), by="day"))
    v %>% 
        left_join(dd, by = "date") %>% 
        na.locf
}

a <- ExpandDates(testDF, 1)
b <- DplyrTest(testDF)

相等性测试:

identical(a$cumwork, as.integer(b$cumwork))
[1] TRUE
identical(a$work, as.integer(b$work))
[1] TRUE
identical(a$date, as.Date(b$date))
[1] TRUE

基准:

library(microbenchmark)
microbenchmark(DplyrTest(testDF), ExpandDates(testDF,1))
Unit: milliseconds
                  expr       min        lq      mean    median        uq       max neval cld
     DplyrTest(testDF) 80.909303 84.337006 91.315057 86.320883 88.818739 173.69395   100   b
ExpandDates(testDF, 1)  1.122384  1.208184  2.521693  1.355564  1.486317  72.23444   100  a