r - 将开始时间和总持续时间转换为每小时经过的时间
问题描述
我有关于开始时间('startTime',一个日期时间变量,POSIXct
)和持续时间('duration_minutes')的数据:
df <- data.frame(id = c(1, 2, 3),
startTime = as.POSIXct(c("2018-01-01 12:15:31",
"2018-01-02 23:43:00",
"2018-01-03 11:00:11")),
duration_minutes = c(315, 120, 45))
我想将开始时间和持续时间转换为每小时经过的时间,从开始时间的小时到持续时间结束时的最后一小时:
df_result <- data.frame(id = c(1, 1, 1, 1, 1, 1, 2, 2, 2, 3),
startTime = c("2018-01-01 12:15:31","2018-01-01 13:00:00",
"2018-01-01 14:00:00","2018-01-01 15:00:00",
"2018-01-01 16:00:00","2018-01-01 17:00:00",
"2018-01-02 23:43:00","2018-01-03 00:00:00",
"2018-01-03 01:00:00",
"2018-01-03 11:00:11"),
duration_minutes = c(44.48, 60, 60, 60, 60, 30.5, 17, 60, 43, 45))
请提供可能的解决方案的建议。
解决方案
另一种可能:
library(data.table)
library(lubridate)
setDT(df)
df[ , ceil_start := ceiling_date(start, "hour", change_on_boundary = TRUE)]
df[ , {
if(difftime(ceil_start, start, units = "min") > dur) {
.SD[ , .(start, dur)]
} else {
end <- start + dur * 60
time <- c(start,
seq(from = ceil_start,
to = floor_date(end, "hour"),
by = "hour"),
end)
.(start = head(time, -1), dur = `units<-`(diff(time), "mins"))
}
},
by = id]
# id start dur
# 1: 1 2018-01-01 12:15:31 44.48333 mins
# 2: 1 2018-01-01 13:00:00 60.00000 mins
# 3: 1 2018-01-01 14:00:00 60.00000 mins
# 4: 1 2018-01-01 15:00:00 60.00000 mins
# 5: 1 2018-01-01 16:00:00 60.00000 mins
# 6: 1 2018-01-01 17:00:00 30.51667 mins
# 7: 2 2018-01-02 23:43:00 17.00000 mins
# 8: 2 2018-01-03 00:00:00 60.00000 mins
# 9: 2 2018-01-03 01:00:00 43.00000 mins
# 10: 3 2018-01-03 11:00:11 45.00000 mins
# 11: 4 2018-01-03 11:35:00 25.00000 mins
# 12: 4 2018-01-03 12:00:00 10.00000 mins
# 13: 5 2018-01-03 00:00:00 60.00000 mins
# 14: 5 2018-01-03 01:00:00 0.00000 mins
解释
转换data.frame
为data.table
( setDT
)。将开始时间四舍五入到最接近的小时(ceiling_date(start, "hour", ...)
。change_on_boundary = TRUE
用于更轻松地处理没有分钟和秒的时间(不在数据中,但经过测试)。
要处理结束时间(开始 + 持续时间)与开始时间在同一小时内的情况(例如 id = 3),请检查舍入时间和开始时间之间的差异是否大于持续时间(if(difftime(ceil_start, start, units = "min") > dur))
)。如果是这样,只需选择开始和持续时间列 ( .SD[ , .(start, dur)
)。
对于其他情况(else
),计算结束时间:end <- start + dur * 60
。创建一个从向上取整的开始时间 ('ceil_start') 到向下取整的结束时间的序列,以小时为增量 ( seq(from = ceil_start, to = floor_date(end, "hour"), by = "hour")
)。与“开始”和“结束”时间连接。返回除最后一次以外的所有时间 (并以分钟 ( )head(time, -1)
为单位计算时间步长之间的差异。`units<-`(diff(time), "mins")
对于 H:M:S = 00:00:00 且持续时间是 60 分钟的倍数(如 id = 5)的时间,当前解决方案给出最后一小时持续时间为 0 分钟的行。在等待更优雅的解决方案时,一种快速而肮脏的方法就是删除持续时间 = 0 的这些行。
数据
请注意,我添加了一个未包含在原始数据中的案例,id = 4(另请参阅我上面的评论)和 id = 5。
df <- data.frame(id = 1:5,
start = as.POSIXct(c("2018-01-01 12:15:31",
"2018-01-02 23:43:00",
"2018-01-03 11:00:11",
"2018-01-03 11:35:00",
"2018-01-03 00:00:00")),
dur = c(315, 120, 45, 35, 60))
推荐阅读
- html - 无法在 flexbox 项目后添加新行换行符
- javascript - 通过比较而不是字符串搜索过滤数字 html 表值
- ip-address - 发送在互联网上而不是在串行监视器上收集的数据(Nodemcu v3)
- c++ - 可执行文件找不到 bin/Data 文件 (bs::framework)
- wordpress - 如何编写使您将代码嵌入到 wordpress 页面的插件?
- python - 如何根据多列计算数据框中子集的总和
- r - 如何通过仅对 R 中现有列的行中的文本进行子集化来创建新列
- python - 从文本文件中读取多行
- css - 如何向 Ant Design 和 React 应用程序添加样式
- javascript - 如何查询包含对象数组中给定键字段的文档?