【问题标题】:Using Datetime Vectors to Filter a Dataframe使用日期时间向量过滤数据框
【发布时间】:2020-11-05 22:32:50
【问题描述】:

我正在尝试使用日期时间对象 (POSIXct) 的向量来过滤数据框。第一个向量包含开始时间,第二个向量包含结束时间。我只想返回属于日期时间对之一的值,即在一对开始时间和结束时间之间。

以下是一些示例数据:

dat <- structure(list(timestamp = structure(c(1604386800, 1604386801, 
                                              1604386802, 1604386803,
                                              1604386804, 1604386805,
                                              1604473200, 1604473201,
                                              1604473202, 1604473203,
                                              1604473204, 1604473205,
                                              1604386800, 1604386801,
                                              1604386802, 1604386803,
                                              1604386804, 1604386805,
                                              1604473200, 1604473201,
                                              1604473202, 1604473203,
                                              1604473204, 1604473205,
                                              1604586800, 1604586801, 
                                              1604586802, 1604586803,
                                              1604586804, 1604586805,
                                              1604586800, 1604586801, 
                                              1604586802, 1604586803,
                                              1604586804, 1604586805),
                                            class = c("POSIXct", "POSIXt"),
                                            tzone = "UTC"),
                      process_time = c(0L, 1L, 2L, 3L, 4L,5L, 0L, 1L, 2L,
                                       3L, 4L, 5L, 0L, 1L, 2L, 3L, 4L, 5L,
                                       0L, 1L, 2L,3L, 4L, 5L, 0L, 1L, 2L,
                                       3L, 4L,5L, 0L, 1L, 2L, 3L, 4L,5L),
                      process_name = c("A", "A", "A", "A", "A", "A", "A",
                                       "A", "A", "A", "A", "A", "B", "B", 
                                       "B", "B", "B", "B", "B", "B", "B",
                                       "B", "B", "B", "C", "C", "C", "C", 
                                       "C", "C", "A", "A", "A", "A", "A",
                                       "A")),
                 class = "data.frame", row.names = c(NA, -36L))

这是我目前所得到的:

library(lubridate)
library(dplyr)

start_time <- ymd_hms(c("2020-11-03 07:00:01", "2020-11-04 07:00:01",
                        "2020-11-05 14:33:21"))
end_time <- ymd_hms(c("2020-11-03 07:00:04", "2020-11-04 07:00:04",
                      "2020-11-05 14:33:24"))

filtered_dat <- dat %>%
  group_by(date(timestamp), process_name) %>%
  filter(timestamp >= start_time & timestamp <= end_time)

我正在寻找的是为每个日期和流程类型过滤掉的第一个和最后一个值。它看起来像:

timestamp             |   process_time    |   process_name
------------------------------------------------------------
2020-11-03 07:00:01   |         1         |        A
2020-11-03 07:00:02   |         2         |        A
2020-11-03 07:00:03   |         3         |        A
2020-11-03 07:00:04   |         4         |        A

2020-11-04 07:00:01   |         1         |        A
2020-11-04 07:00:02   |         2         |        A
2020-11-04 07:00:03   |         3         |        A
2020-11-04 07:00:04   |         4         |        A

2020-11-03 07:00:01   |         1         |        B
2020-11-03 07:00:02   |         2         |        B
2020-11-03 07:00:03   |         3         |        B
2020-11-03 07:00:04   |         4         |        B
       ...                     ...                ...

#spacing added for clarity

似乎正在发生的是开始和结束时间向量正在被回收。因此,它将数据帧的第一行与开始和结束时间向量中的第一项进行比较,然后将第二行与开始和结束时间向量中的第二项进行比较,依此类推。每隔几行它就会得到一个匹配项。

我需要将数据帧的每一行与所有三个日期时间对进行比较,然后再移动到数据帧的下一行。 purrr 似乎就是这里的答案。

【问题讨论】:

    标签: r dplyr purrr lubridate


    【解决方案1】:

    阅读lubridate,我们可以为此目的使用intervals。 如果有多个间隔,那么文档建议我们将其变成一个列表:

    intervals <- list(interval(start_time, end_time))
    

    假设我们要检查某个日期是否在这些时间间隔内,我们可以使用%within% 函数:

    ts <- ymd_hms(2020-11-03 07:00:02)
    ts %within% intervals
    

    结果:

    > ts %within% intervals
    [1]  TRUE FALSE FALSE
    

    或者如果我们想同时检查所有区间:

    > any(ts %within% intervals)
    [1] TRUE
    

    将此应用于您的数据框:

    dat <- dat %>%
      rowwise() %>%
      mutate(within = any(timestamp %within% intervals))
    

    之后您可以使用简单的过滤。

    【讨论】:

    • 我能够通过在您建议的变异之前应用 rowwise() 来完成这项工作。如果没有按行,它似乎将所有内容都标记为 TRUE。有没有办法在不按行调用的情况下做到这一点?
    • 我的错,any(dat$timestamp %within% intervals) 返回TRUE,结果被回收,这导致所有行都是TRUE。事实上,使用rowwise 可以解决这个问题。我更新了回复。谢谢你的收获。
    【解决方案2】:

    您可以使用purrr 中的map2_lgl 来检查每个date 中的any timestamp 是否为between start_timeend_time

    library(dplyr)
    library(lubridate)
    library(purrr)
    
    dat %>%
      group_by(date = date(timestamp), process_name) %>%
      filter(any(map2_lgl(start_time, end_time, ~any(between(timestamp, .x, .y)))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 2022-09-23
      • 2021-09-04
      • 2022-11-23
      • 2021-03-16
      • 1970-01-01
      相关资源
      最近更新 更多