【问题标题】:Split a data table into hourly totals in R在 R 中将数据表拆分为每小时总计
【发布时间】:2015-10-08 18:18:09
【问题描述】:

我有以下数据,其中每一行对应于某次旅行的家庭成员。 由于我们谈论的是家庭成员,因此这些行可能有重叠的时间,如 第 1 行和第 2 行。行程的持续时间以分钟为单位。 IDX 只是一个索引,用于使转换可追溯。

IDX  | ID   | Trip |   StartDateTime    | Duration (in minutes)
1    |  1   |  1   |  2015-01-21 13:00  | 100
2    |  1   |  1   |  2015-01-21 13:00  | 184
3    |  1   |  1   |  2015-01-21 10:00  | 91
4    |  1   |  2   |  2015-01-22 13:00  | 30
5    |  2   |  2   |  2015-01-30 23:00  | 100

现在我想将每个 id、trip、day 的数据拆分为每小时数据,如下所示:

IDX |  ID   | Trip |   StartDateTime      | Duration (in minutes)
1   |  1    |  1   |  2015-01-21 13:00    | 60
1   |  1    |  1   |  2015-01-21 14:00    | 40

请注意,该组的总时长仍为 100,与第一行类似。二、 IDX 取自第一行。但是对于第 4 排,我们没有超过 60 分钟,所以 那一个不会被分裂。结果:

IDX  | ID   | Trip |   StartDateTime      | Duration (in minutes)
4    |  1   |  2   |  2015-01-22 13:00    | 25

现在最难的问题变成了第五排,那一个实际上是穿越一天! 这样一来就变成了:

IDX  | ID   | Trip |   StartDateTime      | Duration (in minutes)
5    |  2   |  2   |  2015-01-30 23:00    | 60
5    |  2   |  2   |  2015-01-31 0:00     | 40

这样的表格可以展开吗?

构建表格的代码:

library(data.table)

data.table(IDX = c(1:5),
           ID  = c(1,1,1,2,2),
           Trip = c(1,1,1,1,2),
           StartDateTime = strptime(c("2015-01-21 13:00","2015-01-21 13:00","2015-01-21 10:00","2015-01-22 13:00","2015-01-30 23:00"), format="%Y-%m-%d %H:%M"),
           Duration = c(100,184,91,30,100)
)

更新 开始时间可以是 13:12 之类的任何时间,但我对确切的开始时间并不感兴趣,所以实际上是每小时。

所以如果开始时间不等于整小时,比如这样:

IDX  | ID   | Trip |   StartDateTime      | Duration (in minutes)
6    |  3   |  1   |  2015-01-30 23:14    | 67

然后我们得到:

IDX  | ID   | Trip |   StartDateTime      | Duration (in minutes)
6    |  3   |  1   |  2015-01-30 23:00    | 46
6    |  3   |  1   |  2015-01-31 0:00     | 11

很抱歉没有澄清这部分,但我认为这是 eddi 解决方案的简单后处理步骤。

谢谢

【问题讨论】:

  • 您的代码最后会引发警告,仅供参考。也许它有什么不对劲。此外,您在所需输出的一部分中创建了一个 Day 列,但它不会出现在接下来的两个中。
  • 哦,对不起,这是不一致的!我已经修好了。此外,错误仅仅是因为 data.table 以另一种格式保存日期时间:)。
  • 开始时间总是整点吗?
  • 不,很遗憾没有。它们是准确的。

标签: r data.table


【解决方案1】:

这与@eddi 的答案非常相似,但使用基础difftime 而不是 lubridate 函数:

# modifying the example:
DT[1, StartDateTime := as.POSIXct("2015-01-21 13:12")]

DT[,{
    t0  = StartDateTime
    t1  = StartDateTime + Duration*60

    h0  = trunc(t0, units="hour") 
    h1  = trunc(t1, units="hour") 
    h   = seq(h0, h1, by="hour")
    nh  = length(h)     

    dur = as.difftime(rep("1",nh), format="%H", units="mins")
    if (h0 <  t0) dur[1 ] = difftime(h0 + as.difftime("1", format="%H", units="mins"), t0)
    if (h1 <  t1) dur[nh] = difftime(t1, h1)
    if (h0 == h1) dur     = difftime(t1, t0)

    list(h = h, dur = dur)
}, by=.(IDX, ID, Trip)]

给了

    IDX ID Trip                   h     dur
 1:   1  1    1 2015-01-21 13:00:00 48 mins
 2:   1  1    1 2015-01-21 14:00:00 52 mins
 3:   2  1    1 2015-01-21 13:00:00 60 mins
 4:   2  1    1 2015-01-21 14:00:00 60 mins
 5:   2  1    1 2015-01-21 15:00:00 60 mins
 6:   2  1    1 2015-01-21 16:00:00  4 mins
 7:   3  1    1 2015-01-21 10:00:00 60 mins
 8:   3  1    1 2015-01-21 11:00:00 31 mins
 9:   4  2    1 2015-01-22 13:00:00 30 mins
10:   5  2    2 2015-01-30 23:00:00 60 mins
11:   5  2    2 2015-01-31 00:00:00 40 mins

【讨论】:

    【解决方案2】:
    dt[, .(IDX, ID, Trip,
           StartDateTime = StartDateTime + 60*seq(0, Duration, 60),
           Duration = diff(c(seq(0, Duration, 60), Duration)))
       , by = 1:nrow(dt)]
    #    nrow IDX ID Trip       StartDateTime Duration
    # 1:    1   1  1    1 2015-01-21 13:00:00       60
    # 2:    1   1  1    1 2015-01-21 14:00:00       40
    # 3:    2   2  1    1 2015-01-21 13:00:00       60
    # 4:    2   2  1    1 2015-01-21 14:00:00       60
    # 5:    2   2  1    1 2015-01-21 15:00:00       60
    # 6:    2   2  1    1 2015-01-21 16:00:00        4
    # 7:    3   3  1    1 2015-01-21 10:00:00       60
    # 8:    3   3  1    1 2015-01-21 11:00:00       31
    # 9:    4   4  2    1 2015-01-22 13:00:00       30
    #10:    5   5  2    2 2015-01-30 23:00:00       60
    #11:    5   5  2    2 2015-01-31 00:00:00       40
    

    以下是对非轮班时间的修改:

    dt[5, StartDateTime := StartDateTime + 14*60]
    
    library(lubridate)
    
    dt[, {dur = diff(c(minute(StartDateTime),
                       tail(seq(0, Duration, 60), -1),
                       Duration + minute(StartDateTime)))
          list(StartDateTime = floor_date(StartDateTime, "hour") + (seq_along(dur)-1)*3600,
               Duration = dur)}
       , by = .(IDX, ID, Trip)]
    #    IDX ID Trip       StartDateTime Duration
    # 1:   1  1    1 2015-01-21 13:00:00       60
    # 2:   1  1    1 2015-01-21 14:00:00       40
    # 3:   2  1    1 2015-01-21 13:00:00       60
    # 4:   2  1    1 2015-01-21 14:00:00       60
    # 5:   2  1    1 2015-01-21 15:00:00       60
    # 6:   2  1    1 2015-01-21 16:00:00        4
    # 7:   3  1    1 2015-01-21 10:00:00       60
    # 8:   3  1    1 2015-01-21 11:00:00       31
    # 9:   4  2    1 2015-01-22 13:00:00       30
    #10:   5  2    2 2015-01-30 23:00:00       46
    #11:   5  2    2 2015-01-31 00:00:00       54
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-15
      • 2017-06-05
      • 2021-04-10
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多