仅给出日期向量,在(不等)日期点之间展开数据

时间:2017-07-03 20:29:17

标签: r date cumsum

其他问题集中在开始和结束日期。 (有关示例,请参阅以下内容 Given start date and end date, reshape/expand data for each day between (each day on a row) 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所指出的那样,数据框中的日期&#39; dd&#39;应该是日期格式。已更新代码以反映此

3 个答案:

答案 0 :(得分:1)

一种可能的方式:

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

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))

答案 1 :(得分:0)

类似的解决方案,基础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)

首先必须将日期转换为日期格式。然后分别创建一个完整日期的向量,并将其与原始数据合并。最终,运行“最后一次观察结转”算法。

答案 2 :(得分:0)

这是一个非常快速的纯碱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中没有任何内容可以提供此值。我还假设&#34; date&#34;字段实际上是@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