【问题标题】:How to filter by multiple time ranges in R?如何在R中按多个时间范围过滤?
【发布时间】:2020-08-24 05:36:42
【问题描述】:

我有一个包含 DateTime 列和一些其他变量的数据框。下面是一个例子:

library(lubridate)
df <- tibble(DateTime = ymd_hms(c("2020-04-06 10:00:00", 
                                                    "2020-04-07 12:30:00", 
                                                    "2020-04-07 14:31:00", 
                                                    "2020-05-05 17:00:00")),
                               Var1 = c(1,2,3,4),
                               var2= c("a","b","c","d"))
df
# A tibble: 4 x 3
          DateTime             Var1 var2 
          <dttm>              <dbl> <chr>
        1 2020-04-06 10:00:00     1 a    
        2 2020-04-07 12:30:00     2 b    
        3 2020-04-07 14:31:00     3 c    
        4 2020-05-05 17:00:00     4 d   

我想过滤行,使其返回一个数据帧,其中 DateTime 中的时间元素介于:

  • 09:15:00 至 12:00:00 或

  • 13:15:00 至 16:30:00 或

  • 17:15:00 至 01:00:00。

这样它会返回以下数据框:

# A tibble: 2 x 3
  DateTime             Var1 var2 
  <dttm>              <dbl> <chr>
1 2020-04-06 10:00:00     1 a    
2 2020-04-07 14:31:00     3 c 

我知道我可以做DateTime &gt;= hms("09:15:00") &amp; DateTime &lt;= hms("12:00:00") 等等,但这似乎太复杂了。有没有更简单的方法?

【问题讨论】:

  • 我没有看到你的逻辑在做你想做的事。例如,df$DateTime &lt; hms("12:00:00") 全部为假。
  • 你可以试试cutting它(有一个“POSIXt”方法),但我认为这同样复杂。

标签: r datetime time filter subset


【解决方案1】:

试试这个:

# library(hms) # hms::as.hms
df %>%
  mutate(DT2 = hms::as.hms(DateTime, tz = "UTC")) %>%
  filter(between(DT2, hms("09:15:00"), hms("12:00:00")) |
           between(DT2, hms("13:15:00"), hms("16:30:00")) |
           DT2 > hms("17:15:00") | DT2 < hms("01:00:00"))
# # A tibble: 2 x 4
#   DateTime             Var1 var2  DT2   
#   <dttm>              <dbl> <chr> <time>
# 1 2020-04-06 10:00:00     1 a     10:00 
# 2 2020-04-07 14:31:00     3 c     14:31 

您无法真正将 POSIXt 与 lubridate 的 Period 类进行直接比较(显然)。另外,我使用了tz="UTC",因为示例数据有一种假设时区的方法,而hms 包必须有不同的假设。您可能需要使用该参数来确保它符合您对数据的期望。

【讨论】:

    【解决方案2】:

    再想一想,你可能会使用lubridate中的interval函数。

    不幸的是,它们只适用于日期时间对象。所以你必须有点hacky并添加任意日期:

    library(dplyr)
    library(lubridate)
    library(purrr)
    my.intervals <- c(dmy_hms("1/1/00 09:15:00") %--% dmy_hms("1/1/00 12:00:00"),
                      dmy_hms("1/1/00 13:15:00") %--% dmy_hms("1/1/00 16:30:00"),
                      dmy_hms("1/1/00 17:15:00") %--% dmy_hms("1/1/00 23:59:59"),
                      dmy_hms("1/1/00 00:00:00") %--% dmy_hms("1/1/00 01:00:00"))
    
    df %>%
      mutate(Time = dmy_hms(paste0("01/01/00 ",format(DateTime,"%H:%M:%S")))) %>% 
      dplyr::filter(map_lgl(Time, ~ any(.x %within% my.intervals))) %>%
      dplyr::select(-Time)
    # A tibble: 2 x 3
      DateTime             Var1 var2 
      <dttm>              <dbl> <chr>
    1 2020-04-06 10:00:00     1 a    
    2 2020-04-07 14:31:00     3 c   
    

    【讨论】:

      【解决方案3】:

      使用cut 的“POSIXt”方法是一种选择:

      library(dplyr)
      
      df %>%
        filter(cut(as.POSIXct(paste0(Sys.Date(), format(DateTime, "%H:%M:%S"))), 
                   breaks=as.POSIXct(
                     c("09:15:00","12:00:00","13:15:00","16:30:00","17:15:00","01:00:00"), 
                     format="%H:%M:%S"), labels=FALSE) %in% c(2,4,6))
      
      # A tibble: 2 x 3
        DateTime             Var1 var2 
        <dttm>              <dbl> <chr>
      1 2020-04-06 10:00:00     1 a    
      2 2020-04-07 14:31:00     3 c 
      

      有点笨拙,但不需要任何外部包。可能需要调整休息时间以包含结尾,可能会返回 1 秒。

      【讨论】:

        猜你喜欢
        • 2014-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-07
        • 2017-08-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多