【问题标题】:R -- Expand date range into panel data by groupR -- 按组将日期范围扩展到面板数据
【发布时间】:2014-06-05 18:17:38
【问题描述】:

我有按两个变量(idtype)分组的日期范围,这些变量当前存储在名为data 的数据框中。我的目标是扩展日期范围,以便在日期范围内的每一天都有一行,其中包括相同的 idtype

这是一个sn-p重现数据框的例子:

data <- structure(list(id = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2), type = c("a", 
"a", "b", "c", "b", "a", "c", "d", "e", "f"), from = structure(c(1235199600, 
1235545200, 1235545200, 1235631600, 1235631600, 1242712800, 1242712800, 
1243058400, 1243058400, 1243231200), class = c("POSIXct", "POSIXt"
), tzone = ""), to = structure(c(1235372400, 1235545200, 1235631600, 
1235890800, 1236236400, 1242712800, 1243058400, 1243231200, 1243144800, 
1243576800), class = c("POSIXct", "POSIXt"), tzone = "")), .Names = c("id", 
"type", "from", "to"), row.names = c(700L, 753L, 2941L, 2178L, 
 2959L, 679L, 2185L, 12L, 802L, 1796L), class = "data.frame")

这是数据集的可视化表示:

id  type  from        to
1   a     2009-02-21  2009-02-23
1   a     2009-02-25  2009-02-25
1   b     2009-02-25  2009-02-26
1   c     2009-02-25  2009-03-01
1   b     2009-05-26  2009-03-05
2   a     2009-05-26  2009-05-19
2   c     2009-05-19  2009-05-23
2   d     2009-05-19  2009-05-25
2   e     2009-05-23  2009-05-24
2   f     2009-05-25  2009-05-29

这是预期结果的直观表示:

id  type  date
1   a     2009-02-21
1   a     2009-02-22
1   a     2009-02-23
1   b     2009-02-25
1   b     2009-02-26
1   c     2009-02-26
1   c     2009-02-27
1   c     2009-02-28
1   c     2009-03-01
...
2   f     2009-05-25
2   f     2009-05-26
2   f     2009-05-27
2   f     2009-05-28
2   f     2009-05-29

我发现了几篇类似的帖子(linklink),它们有助于为我提供一个起点。我尝试使用 plyr 解决方案:

data2 <- adply(data, 1, summarise, date = seq(data$from, data$to))[c('id', 'type')]

但是,这会导致错误:

Error: 'from' must be of length 1

我也尝试过使用 data.table 解决方案:

data[, list(date = seq(from, to)), by = c('id', 'type')]

但是,这给了我一个不同的错误:

Error in `[.data.frame`(data, , list(date = seq(from, to)), by = c("id",  : 
unused argument (by = c("id", "type"))

任何关于如何解决这些错误(或使用不同方法)的想法将不胜感激。

【问题讨论】:

    标签: r date seq


    【解决方案1】:

    1) by 这是一个使用 R 基础的 by 的三行答案。首先,我们将日期转换为 "Date" 类,给出 data2。然后我们应用 f 对每一行进行真正的工作,最后我们 rbind 将结果行放在一起:

    data2 <- transform(data, from = as.Date(from), to = as.Date(to))
    
    f <- function(x) with(x, data.frame(id, type, date = seq(from, to, by = "day")))
    do.call("rbind", by(data, 1:nrow(data), f))
    

    2) data.table 使用与 data.table 相同的data2,我们这样做:

    library(data.table)
    
    dt <- data.table(data2)
    dt[, list(id, type, date = seq(from, to, by = "day")), by = 1:nrow(dt)]
    

    2a) data.table 或者 dt 来自 (2) 和 f 来自 (1):

    dt[, f(.SD), by = 1:nrow(dt)]
    

    3) dplyr 这里data2f 来自(1):

    data2 %>% rowwise %>% do(f(.)) %>% ungroup
    

    4) dplyr/purrr 这里 data2 来自 (1)。

    library(dplyr)
    library(purrr)
    
    data2 %>%
      pmap(function(..., from, to) tibble(..., date = seq(from, to, by = "day"))) %>%
      bind_rows
    

    更新一些改进。

    【讨论】:

    • 太棒了——谢谢!包含解决方案的多个实现的额外功劳。
    【解决方案2】:

    这是使用基函数执行此类转换的一种方法

    do.call(rbind,Map(function(id,type,from,to) {
        dts <- seq(from=from, to=to, by="1 day")
        dur <- length(dts)
        data.frame(
            id=rep(id, dur), 
            type=rep(type,dur),
            date=dts
        )
    }, data$id, data$type, data$from, data$to))
    

    输出的第一块是

       id type                date
    1   1    a 2009-02-21 02:00:00
    2   1    a 2009-02-22 02:00:00
    3   1    a 2009-02-23 02:00:00
    4   1    a 2009-02-25 02:00:00
    5   1    b 2009-02-25 02:00:00
    6   1    b 2009-02-26 02:00:00
    7   1    c 2009-02-26 02:00:00
    8   1    c 2009-02-27 02:00:00
    9   1    c 2009-02-28 02:00:00
    10  1    c 2009-03-01 02:00:00
    11  1    b 2009-02-26 02:00:00
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-30
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多