【问题标题】:Count time stamps in different time intervals - issue with interval which spans midnight计算不同时间间隔的时间戳 - 跨越午夜的间隔问题
【发布时间】:2018-02-04 05:14:59
【问题描述】:

我有一个带有H:M 格式(“时间”)时间戳的数据框(“观察”)。在第二个数据帧(“间隔”)中,我有由“From”和“Till”变量定义的时间范围,也是H:M 格式。

我想计算每个区间内的观察次数。我一直在使用来自data.table 的between,当包含日期时,它一直在正常工作。

但是,现在我只有时间戳,没有日期。这会导致跨越午夜 (20:00 - 05:59) 的时间间隔出现一些问题。这些时间没有计入我尝试过的代码中。

以下示例

interval.data <- data.frame(From = c("14:00", "20:00", "06:00"), Till = c("19:59", "05:59", "13:59"), stringsAsFactors = F)
observations <- data.frame(Time = c("14:32", "15:59", "16:32", "21:34", "03:32", "02:00", "00:00", "05:57", "19:32", "01:32", "02:22", "06:00", "07:50"), stringsAsFactors = F)

interval.data
#        From     Till
# 1: 14:00:00 19:59:00
# 2: 20:00:00 05:59:00 # <- interval including midnight
# 3: 06:00:00 13:59:00

observations
#        Time
#  1: 14:32:00
#  2: 15:59:00
#  3: 16:32:00
#  4: 21:34:00 # Row 4-8 & 10-11 falls in 'midnight interval', but are not counted
#  5: 03:32:00 # 
#  6: 02:00:00 #
#  7: 00:00:00 #
#  8: 05:57:00 #
#  9: 19:32:00
# 10: 01:32:00 # 
# 11: 02:22:00 #
# 12: 06:00:00
# 13: 07:50:00

library(data.table)
library(plyr)
adply(interval.data, 1, function(x, y) sum(y[, 1] %between% c(x[1], x[2])), y = observations)

#    From  Till V1
# 1 14:00 19:59  4
# 2 20:00 05:59  0 # <- zero counts - wrong!
# 3 06:00 13:59  2

【问题讨论】:

  • 这些总是你的时间间隔,还是这只是更大数据集的一个小例子?
  • 更大集合的相同结构
  • 使用带有 1 边距的 adply 会使 data.table 的使用变得无关紧要。

标签: r data.table lubridate


【解决方案1】:

一种方法是在data.table 中使用非等值连接,并使用它们的辅助函数as.ITime 处理时间字符串。

您会遇到跨越午夜的时间间隔的问题,但是,应该只有其中之一。由于您对每个“组”区间的观察次数感兴趣,因此您可以将此组视为其他组的“非”组。

例如,首先将您的data.frame 转换为data.table

library(data.table)

## set your data.frames as `data.table`
setDT(interval.data)
setDT(observations)

然后使用as.ITime转换为时间的整数表示

## convert time stamps
interval.data[, `:=`(FromMins = as.ITime(From),
                     TillMins = as.ITime(Till))]

observations[, TimeMins := as.ITime(Time)]
## you could combine this step with the non-equi join directly, but I'm separating it for clarity

您现在可以使用非 equi 连接来查找每个时间所在的间隔。注意那些返回“NA”的时间实际上是那些落在午夜跨度间隔内的时间

interval.data[
  observations
  , on = .(FromMins <= TimeMins, TillMins > TimeMins)
  ]

#      From  Till FromMins TillMins  Time
# 1:  14:00 19:59      872      872 14:32
# 2:  14:00 19:59      959      959 15.59
# 3:  14:00 19:59      992      992 16:32
# 4:     NA    NA     1294     1294 21:34
# 5:     NA    NA      212      212 03:32
# 6:     NA    NA      120      120 02:00
# 7:     NA    NA        0        0 00:00
# 8:     NA    NA      357      357 05:57
# 9:  14:00 19:59     1172     1172 19:32
# 10:    NA    NA       92       92 01:32
# 11:    NA    NA      142      142 02:22
# 12: 06:00 13:59      360      360 06:00
# 13: 06:00 13:59      470      470 07:50

然后要获得各组区间的观察次数,您只需将.N按每个时间点分组即可,可以将其链接到上述语句的末尾

interval.data[
  observations
  , on = .(FromMins <= TimeMins, TillMins > TimeMins)
][
  , .N
  , by = .(From, Till)
]

#     From  Till N
# 1: 14:00 19:59 4
# 2:    NA    NA 7
# 3: 06:00 13:59 2

NA 组对应于跨越午夜的组

【讨论】:

  • 您可以在这里使用as.ITime,而不是转换为分钟吗?
  • @Henrik - 是的,当然!我总是在data.table 中了解ITime...我会更新
【解决方案2】:

我刚刚调整了您的代码以获得所需的结果。希望这会有所帮助!

adply(interval.data, 1, function(x, y) 
  if(x[1] > x[2]) return(sum(y[, 1] %between% c(x[1], 23:59), y[, 1] %between% c(00:00, x[2]))) else return(sum(y[, 1] %between% c(x[1], x[2]))), y = observations)

输出是:

   From  Till V1
1 14:00 19:59  4
2 20:00 05:59  7
3 06:00 13:59  2

【讨论】:

  • 这是完美的。只需要引用“23:59”和“00:00”。虽然它确实适用于上述示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-08
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多