【问题标题】:Mapping ymd_hms time into 15 minute time intervals将 ymd_hms 时间映射为 15 分钟的时间间隔
【发布时间】:2022-01-07 14:27:50
【问题描述】:

我正在寻找以下问题的 data.table 解决方案。

假设我有以下数据集:

library(data.table)
library(lubridate)

DT <- data.table(date = c("2019-01-01 00:03:04", 
                          "2019-01-01 00:07:03",
                          "2019-01-01 00:15:23",
                          "2019-01-01 00:16:28",
                          "2019-01-01 00:21:30"))
DT
         date
1: 2019-01-01 00:03:04
2: 2019-01-01 00:07:03
3: 2019-01-01 00:15:23
4: 2019-01-01 00:16:28
5: 2019-01-01 00:21:30


我希望将每个日期映射为每天 15 分钟的间隔。所以最终的数据集看起来像:

   date                    date_15min_grp
1: 2019-01-01 00:03:04              1
2: 2019-01-01 00:07:03              1
3: 2019-01-01 00:15:23              2
4: 2019-01-01 00:16:28              2
5: 2019-01-01 00:21:30              2

这些组在一天级别上是唯一的,因此 2019-01-01 00:03:042019-01-02 00:03:04 都将返回值 1。我当前的解决方案是提取每天的小时/分钟/秒部分。然后我将添加这些值(转换为分钟后),将它们除以 60,并尝试将每个值映射到最近的“组”。但这似乎又慢又不优雅。

非常感谢 data.table/lubridate。

非常感谢!

【问题讨论】:

  • 我很确定有一个 cut 方法,其间隔规范可以设置为 POSIXct 向量的“15 分钟”。

标签: r dplyr data.table lubridate


【解决方案1】:

请在下面找到使用data.tablelubridate 的解决方案

Reprex

  • 代码
library(data.table)
library(lubridate)

DT[, date_15min_grp := fcase(minute(date) < 15, 1,
                             minute(date) < 30, 2,
                             minute(date) < 45, 3,
                             default = 4)][]
  • 输出
#>                   date date_15min_grp
#> 1: 2019-01-01 00:03:04              1
#> 2: 2019-01-01 00:07:03              1
#> 3: 2019-01-01 00:15:23              2
#> 4: 2019-01-01 00:16:28              2
#> 5: 2019-01-01 00:21:30              2

reprex package (v2.0.1) 于 2021 年 11 月 30 日创建


作为您评论的后续行动

  • 代码
library(data.table)
library(lubridate)

DT[, date_15min_grp := fcase(minute(date) < 15, hour(date)*4 + 1,
                             minute(date) < 30, hour(date)*4 + 2,
                             minute(date) < 45, hour(date)*4 + 3,
                             minute(date) < 60, hour(date)*4 + 4)][]
  • 输出
#>                   date date_15min_grp
#> 1: 2019-01-01 00:03:04              1
#> 2: 2019-01-01 00:07:03              1
#> 3: 2019-01-01 00:15:23              2
#> 4: 2019-01-01 00:16:28              2
#> 5: 2019-01-01 00:21:30              2

reprex package (v2.0.1) 于 2021-12-01 创建

【讨论】:

  • 对不起,我的描述不清楚。这不仅基于分钟,还基于小时。所以2019-01-01 00:21:302019-01-01 01:21:30 应该返回不同的值。抱歉不清楚。
  • 嗨@plausibly_exogenous,请在我的编辑上方找到您的评论。希望这就是你要找的东西 ;-) 干杯。
  • 是的!非常感谢。勾选。
  • 嗨@plausibly_exogenous,我看到你更喜欢验证 Merijn van Tilborg 的答案。这是你的选择,我尊重它,没有任何问题。但是请注意,您刚刚验证的答案比我建议的要慢 7.8 倍;在你的问题结束时,你似乎表明你想要一个快速有效的解决方案。
  • 嗨@lovalery。抱歉,我不太了解有关验证的礼仪。我通常只勾选最近运行良好且简洁的解决方案。但我现在意识到这有点武断,可以被认为是粗鲁的。道歉。我已恢复您的复选标记。感谢您一直以来的贡献。
【解决方案2】:

您应该看看滑块包是否适合您。它既可以按行切割数据,也可以应用 apply / purrr 等功能。

library(tibble)
library(slider)
library(dplyr)

f <- data.frame(date = c(as.POSIXlt("2019-01-01 00:03:04"), 
         as.POSIXlt("2019-01-01 00:07:03"), as.POSIXlt("2019-01-01 00:15:23"),
         as.POSIXlt("2019-01-01 00:16:28"), as.POSIXlt("2019-01-01 00:21:30"), 
         as.POSIXlt("2019-01-01 00:22:03"), as.POSIXlt("2019-01-01 00:25:23"),
         as.POSIXlt("2019-01-01 00:36:28"), as.POSIXlt("2019-01-01 00:41:30"), 
         as.POSIXlt("2019-01-01 00:47:03"), as.POSIXlt("2019-01-01 00:48:23"),
         as.POSIXlt("2019-01-01 00:51:28"), as.POSIXlt("2019-01-01 00:51:30"), 
         as.POSIXlt("2019-01-01 00:57:03"), as.POSIXlt("2019-01-01 00:61:23"),
         as.POSIXlt("2019-01-01 00:66:28"))) %>% arrange(date)

g <- block(f, f$date, period = "minute", every=15)

【讨论】:

  • 为什么每个元素都需要as.POSIXlt?就做f &lt;- data.frame(date = as.POSIXlt(c(....)))
【解决方案3】:
library(data.table)
library(lubridate)

DT <- data.table(date = c("2019-01-01 00:03:04", 
                          "2019-01-01 00:07:03",
                          "2019-01-01 00:15:23",
                          "2019-01-01 00:16:28",
                          "2019-01-01 00:21:30"))

# if every new day falls in a new group
DT[, date_15min_grp := .GRP, by = floor_date(ymd_hms(date), "15 minutes")]

# if every new day needs to fall in the same group
DT[, date_15min_grp := .GRP, by = format(floor_date(ymd_hms(date), "15 minutes"), "%H:%M:%S")]

【讨论】:

  • 这个解决方案有效,也非常简洁。非常感谢!
【解决方案4】:

两件事:

  1. 我认为您的第 5 行应该是第 2 组,因为它在当天的 00:30:00 之前。请澄清这是否不正确。

  2. 您说需要每天,但您的数据只包括一天;我将对其进行扩充以演示其每天的计算。

DT[,date := as.POSIXct(date)]
DT2 <- rbindlist(list(DT, DT[, date := date + 86400]))
DT2
#                    date   grp
#                  <POSc> <int>
#  1: 2019-01-02 00:03:04     1
#  2: 2019-01-02 00:07:03     1
#  3: 2019-01-02 00:15:23     2
#  4: 2019-01-02 00:16:28     2
#  5: 2019-01-02 00:21:30     2
#  6: 2019-01-02 00:03:04     1
#  7: 2019-01-02 00:07:03     1
#  8: 2019-01-02 00:15:23     2
#  9: 2019-01-02 00:16:28     2
# 10: 2019-01-02 00:21:30     2

还有小组作业:

DT2[, day := format(date, format = "%Y%m%d")
  ][, grp := findInterval(date, seq(lubridate::floor_date(min(date), unit = "hours"), max(date) + 3600, by = "15 mins")), by = day][]
#                    date   grp      day
#                  <POSc> <int>   <char>
#  1: 2019-01-02 00:03:04     1 20190102
#  2: 2019-01-02 00:07:03     1 20190102
#  3: 2019-01-02 00:15:23     2 20190102
#  4: 2019-01-02 00:16:28     2 20190102
#  5: 2019-01-02 00:21:30     2 20190102
#  6: 2019-01-02 00:03:04     1 20190102
#  7: 2019-01-02 00:07:03     1 20190102
#  8: 2019-01-02 00:15:23     2 20190102
#  9: 2019-01-02 00:16:28     2 20190102
# 10: 2019-01-02 00:21:30     2 20190102

【讨论】:

  • 嗨@r2evans,是的,你是对的,它应该是第 2 组。谢谢你的解决方案。我测试了它,效果很好。感谢您一直以来的帮助。
  • @r2evans,使用 data.table 和 lubridate 有更强大的方法可以做到这一点,并且可以简化为单个 oneliner,其中所有内容都在 by 子句中完成。 DT[, date_15min_grp := .GRP, by = format(floor_date(ymd_hms(date), "15 minutes"), "%H:%M:%S")]
  • 我对@9​​87654325@不太熟练,谢谢。
【解决方案5】:

我的三德包单线:

DT$date <- as.POSIXct(DT$date)
DT$interval <- santoku::chop_width(DT$date, minutes(15))
DT
##                   date                                   interval
## 1: 2019-01-01 00:03:04 [2019-01-01 00:03:04, 2019-01-01 00:18:04)
## 2: 2019-01-01 00:07:03 [2019-01-01 00:03:04, 2019-01-01 00:18:04)
## 3: 2019-01-01 00:15:23 [2019-01-01 00:03:04, 2019-01-01 00:18:04)
## 4: 2019-01-01 00:16:28 [2019-01-01 00:03:04, 2019-01-01 00:18:04)
## 5: 2019-01-01 00:21:30 [2019-01-01 00:18:04, 2019-01-01 00:33:04)

标签可以自定义,例如试试chop_width(DT$date, minutes(15), labels = lbl_dash(fmt = "%H:%M:%S"))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    相关资源
    最近更新 更多