R按小时划分间隔

R按小时划分间隔,r,time,R,Time,可能很简单,但很难解决,在网上寻找答案,但它们通常与cut和快照有关,而不是重叠的时间间隔 require(data.table) x = data.table(start=c("2017-04-18 18:05:00","2017-04-18 18:00:00", "2017-04-18 21:05:00", "2017-04-18 16:05:00"), end=c("2017-04-18 19:05:00","2017-04-18 21:30:00", "

可能很简单,但很难解决,在网上寻找答案,但它们通常与
cut
和快照有关,而不是重叠的时间间隔

require(data.table)
x = data.table(start=c("2017-04-18 18:05:00","2017-04-18 18:00:00", 
"2017-04-18 21:05:00", "2017-04-18 16:05:00"), 
               end=c("2017-04-18 19:05:00","2017-04-18 21:30:00",
"2017-04-18 22:00:00", "2017-04-18 16:10:00"))
我们有4个观测值,我需要将其分配到相应的每小时窗口

                 start                 end
1: 2017-04-18 18:05:00 2017-04-18 19:05:00
2: 2017-04-18 18:00:00 2017-04-18 21:30:00
3: 2017-04-18 21:05:00 2017-04-18 22:00:00
4: 2017-04-18 16:05:00 2017-04-18 16:10:00
例如,第一个在18:00时段有55分钟,19:00时段有5分钟,下一个在18:00、19:00、20:00和21:00时段有60分钟,第三个在21:00时段有55分钟,最后一个在16:00时段有5分钟

结果应该如下(如果我的基本手册添加错误,请道歉;)


当然,有一种直接的方法可以按分钟分割序列,并按分割/间隔进行计数,但我相信这个问题非常常见,必须有一种直接的方法。我最好也有0值窗口,但如果需要,我可以对它们进行排序

这是一个使用
dplyr的解决方案

首先,定义一个助手函数
find_slots
,以生成
start
end
之间的所有小时数。接下来计算
Q

最后,通过对每个插槽进行分组来总结数据

library(dplyr)

find_slots <- function(a, b){
    slots = seq(a-minute(a)*60-second(a),
                b-minute(b)*60-second(b),
                "hour")

    dateseq = slots
    dateseq[1] = a
    r = c(dateseq, b)

    d = as.numeric(difftime(r[-1], r[-length(r)], unit = 'min'))

    data.frame(slot = slots, Q = d)
}

x %>%
    rowwise %>%
    do(find_slots(.$start, .$end)) %>%
    ungroup() %>%
    group_by(slot) %>%
    summarize(Q = sum(Q))
编辑:使用数据表

(可能更快,但我对data.table不太有经验)

还可以使用
fasttime
库来加速对日期时间的解析

library(fasttime)
library(data.table)

x = data.table(start=c("2017-04-18 18:05:00","2017-04-18 18:00:00", 
"2017-04-18 21:05:00", "2017-04-18 16:05:00"), 
               end=c("2017-04-18 19:05:00","2017-04-18 21:30:00",
"2017-04-18 22:00:00", "2017-04-18 16:10:00"))

find_slots2 <- function(a, b){
    a = fasttime::fastPOSIXct(a)
    b = fasttime::fastPOSIXct(b)
    slots = seq(a-data.table::minute(a)*60-data.table::second(a)*60,
                b-data.table::minute(b)*60-data.table::second(b)*60,
                "hour")

    hourseq = c(a, slots[-1], b)

    d = difftime(hourseq[-1], hourseq[-length(hourseq)], unit = 'min')

    list(slot = slots, Q = d)
}

x[, find_slots2(start, end), by = 1:nrow(x)][order(slot), .(Q = as.numeric(sum(Q))), by = slot]
库(fasttime)
库(数据表)
x=数据表(开始=c(“2017-04-18 18:05:00”,“2017-04-18 18:00:00”),
"2017-04-18 21:05:00", "2017-04-18 16:05:00"), 
结束=c(“2017-04-18 19:05:00”,“2017-04-18 21:30:00”,
"2017-04-18 22:00:00", "2017-04-18 16:10:00"))

find_slots2有一个函数
lubridate::interval()
,在这里可能很有用

您是如何获得
Q
中的值的?Q是属于某个间隔的分钟数,因此,例如,案例4有5分钟(2017-04-18 16:05:00-2017-04-18 16:10:00),而所有其他案例都没有,因此结果是5Nina,您将如何在此处使用lubridate::interval()?它对于处理间隔非常有用,因此所有条目都可以转换为间隔,但是从那里呢?解决方案在逻辑上似乎是正确的,它在一分钟内就出现了错误(a)*60:二进制运算符的非数值参数有什么想法可以加快它的速度吗?我添加了一个data.table版本,可能更快。谢谢,只是测试,顺便说一句,fasttime操作可以在函数之前安全地移动,我认为在表上应用比在行上应用要快。表的版本要慢近50%——在80k记录(还有一个属性要分组)上,dplyr有210秒和data.table 290秒
                 slot   Q
1 2017-04-18 16:00:00   5
2 2017-04-18 18:00:00 115
3 2017-04-18 19:00:00  65
4 2017-04-18 20:00:00  60
5 2017-04-18 21:00:00  85
6 2017-04-18 22:00:00   0
library(fasttime)
library(data.table)

x = data.table(start=c("2017-04-18 18:05:00","2017-04-18 18:00:00", 
"2017-04-18 21:05:00", "2017-04-18 16:05:00"), 
               end=c("2017-04-18 19:05:00","2017-04-18 21:30:00",
"2017-04-18 22:00:00", "2017-04-18 16:10:00"))

find_slots2 <- function(a, b){
    a = fasttime::fastPOSIXct(a)
    b = fasttime::fastPOSIXct(b)
    slots = seq(a-data.table::minute(a)*60-data.table::second(a)*60,
                b-data.table::minute(b)*60-data.table::second(b)*60,
                "hour")

    hourseq = c(a, slots[-1], b)

    d = difftime(hourseq[-1], hourseq[-length(hourseq)], unit = 'min')

    list(slot = slots, Q = d)
}

x[, find_slots2(start, end), by = 1:nrow(x)][order(slot), .(Q = as.numeric(sum(Q))), by = slot]