R取消列表和乘法(日期间隔)

时间:2016-10-20 15:07:19

标签: r dataframe

尝试计算2个日期之间的案例数,有表包含数字和时间间隔,我想创建包含日期和案例总和的输出表。容易(和解决)的问题是:

 df <- data.frame(person = c("A", "B", "C"), start = c("2014-01-01", "2014-01-03", "2014-01-04"), stop = c("2014-01-02", "2014-01-06", "2014-01-04") )
 df

 f1 = function() {  #keeping dates
   as.data.frame(table(unlist(apply(df[-1], 1, 
                                    function(x) as.character(seq(as.Date(x[1], "%Y-%m-%d"), 
                                                                 as.Date(x[2], "%Y-%m-%d"), "1 day"))))))}
 f1()

它会返回

        Var1 Freq
1 2014-01-01    1
2 2014-01-02    1
3 2014-01-03    1
4 2014-01-04    2
5 2014-01-05    1
6 2014-01-06    1

我需要的是总结第一列,使用像这样的输入数据

 df <- data.frame(cases = c(5, 2, 2), start = c("2014-01-01", "2014-01-03", "2014-01-04"), stop = c("2014-01-02", "2014-01-06", "2014-01-04") )

它应该返回

        Var1 cases
1 2014-01-01    5
2 2014-01-02    5
3 2014-01-03    2
4 2014-01-04    4
5 2014-01-05    2
6 2014-01-06    2

也许甚至不会是不公开的情况,我可以用什么来计算每天的病例数?如果日期在开始和结束之间有效但数据中没有任何出现,有没有办法显示0值

修改

Aichao的回答是我所需要的 - 唯一遗漏的是获得0总和,例如

df <- data.frame(cases = c(5, 2, 2), 
start = c("2014-01-01", "2014-01-04", "2014-01-04"), 
stop = c("2014-01-02", "2014-01-06", "2014-01-04") )

获取

        Var1 x
1 2014-01-01 5
2 2014-01-02 5
3 2014-01-03 0
4 2014-01-04 4
5 2014-01-05 2
6 2014-01-06 2

1 个答案:

答案 0 :(得分:1)

这是一个与您使用f1

所做的一致的解决方案
f2 <- function(df) {
  df2 <- do.call(rbind, lapply(1:nrow(df), function(i) {
    Var1 <- as.character(seq(as.Date(df$start[i],format="%Y-%m-%d"),
                             as.Date(df$stop[i],format="%Y-%m-%d"),"day"))
    cases <- rep(df$cases[i],length(Var1))
    data.frame(Var1,cases)
  }))
  aggregate(df2[,-1], by=list(Var1=df2[,1]), FUN=sum)
}

f2

  1. df2中的每一行,从df$startdf$stop的日期序列构建数据框df。在这里,lapply用于循环df的每一行,并且每行的cases重复以匹配生成的日期序列的length。然后使用rbind按行组合每个数据框。
  2. 然后aggregate(来自stats个包裹)此df2按日期(即Var1)和sum向上cases
  3. 使用您的数据:

    f2(df)
    ##        Var1 x
    ##1 2014-01-01 5
    ##2 2014-01-02 5
    ##3 2014-01-03 2
    ##4 2014-01-04 4
    ##5 2014-01-05 2
    ##6 2014-01-06 2
    

    使用0作为cases填写缺失日期的一种方法是从上述解决方案中获取汇总结果,并创建跨越日期范围的新日期序列。这将为新输出创建Var1列。然后,将案例从旧结果复制到与日期匹配的新输出:

    f2 <- function(df) {
      df2 <- do.call(rbind, lapply(1:nrow(df), function(i) {
        ## note that we do not convert to characters here because we want to use these later to form the sequence
        Var1 <- seq(as.Date(df$start[i],format="%Y-%m-%d"),
                    as.Date(df$stop[i],format="%Y-%m-%d"),"day")
        cases <- rep(df$cases[i],length(Var1))
        data.frame(Var1,cases)
      }))
      df2 <- aggregate(df2[,-1], by=list(Var1=df2[,1]), FUN=sum)
      ## sort previous result by date
      df2 <- df2[order(df2[,1]),]
      ## create new sequence spanning range
      Var1 <- as.character(seq(df2[1,1],df2[nrow(df2),1],"day"))
      ## create cases of zeros matching Var1 in length
      cases <- rep(0,length(Var1))
      ## copy over cases from previous result that matches date
      cases[na.omit(match(as.character(df2[,1]),Var1))] <- df2[,2]
      ## output as data frame
      data.frame(Var1,cases)
    }
    

    在您更新的数据上:

    f2(df)
    ##        Var1 cases
    ##1 2014-01-01     5
    ##2 2014-01-02     5
    ##3 2014-01-03     0
    ##4 2014-01-04     4
    ##5 2014-01-05     2
    ##6 2014-01-06     2