Обнаружение двух последовательных дней и подмножество / фильтр определенного периода времени среди двух последовательных дат в data.frame в R

#r #dataframe #datetime #time-series #subset

#r #dataframe #дата-время #временные ряды #подмножество

Вопрос:

У меня есть data.frame информации о погоде по этой ссылке https://www.dropbox.com/s/60p93cmhgdi93yd/weather(2).xlsx?dl=0

Эта информация о погоде записывается каждые 4-6 минут (в зависимости от дней). Я хотел извлечь определенный период времени из data.frame среди двух последовательных дней. Например, я хотел бы извлечь период времени с 9:45 утра 2018-4-9 по 9:45 утра 2018-4-10 и с 9:45 утра 2018-4-23 по 9:45 утра 2018-4-24, …..

Я также создал поддельный data.frame, как рекомендовано, но мой фактический data.frame содержит более 60 групп по два последовательных дня:

 df1 <- data.frame(
  datetime = seq(
    as.POSIXct("2018-4-9 00:00"), as.POSIXct("2018-4-10 00:00"), by = "60 min"))
df2 <- data.frame(
  datetime = seq(
    as.POSIXct("2018-4-23 00:00"), as.POSIXct("2018-4-24 00:00"), by = "60 min"))
df3 <- data.frame(
  datetime = seq(
    as.POSIXct("2018-5-7 00:00"), as.POSIXct("2018-5-8 00:00"), by = "60 min"))
df <- rbind(df,df2,df3)
  

Я подумал о нескольких способах сделать это:

  1. Я могу использовать пакет ‘lubridate’ для преобразования времени в числовую форму, чтобы я мог определить продолжительность определенных чисел, которые нужно извлечь. Но мне также нужно сгруппировать каждые две последовательные даты вместе, чтобы рассчитать продолжительность. У меня был такой код
 daystart <- hm("0:0")

weather$date1 <- sort(as.Date(weather$Date))
a <- split(weather$date1,cumsum(c(TRUE,diff(weather$date1)>1)))
weather <- data.frame(weather,a)
#this does not work

weather <- weather %>%
  group_by(group #the grouped consecutive days) %>%
  mutate(dur = as.numeric(Time-daystart)) %>%
  filter(dur > xxx amp; dur < xxxx)
#I was thinking to do it this way
  

сгруппированные два последовательных дня вместе, но возвращают идентификатор группы только один раз, поэтому его нельзя объединить с weather data.frame (я думаю, это проблема). Кроме того, я не уверен, как рассчитать продолжительность для каждых двух последовательных дней, но я думаю, что это можно сделать, как только я смогу сгруппировать последовательные дни вместе.

  1. Я также подумал об использовании «filter» и «ifelse» для извлечения времени
 weather <- weather %>%
  filter(
    if(diff(Date) <= 1){
      Time <= trapstart
    }
    else{
    NULL
    }
  )
  

Что-то вроде этого, но это не работает (конечно).

Я действительно хочу создать код примерно так (на самом деле это не код)

 weather <- weather %>%
  filter(
    if("these are two consecutive days"){
      "9:45 of the first day < Time <= 9:45 the second day"
    }
    else{
    NULL
    }
  )
  

Время записи этого кадра данных не согласуется каждый день, поэтому время записи может отличаться в разные дни, а записанные точки данных отличаются в разные дни.

Вот что я ожидаю от результата (представьте, что у меня есть только 5 записей каждый день):

 Date    Time    DateTime
4/9/2018    9:46    4/9/2018 9:46
4/9/2018    15:34   4/9/2018 15:34
4/9/2018    22:44   4/9/2018 22:44
4/10/2018   4:34    4/10/2018 4:34
4/10/2018   7:09    4/10/2018 7:09
4/10/2018   9:44    4/10/2018 9:44
4/23/2018   9:46    4/23/2018 9:46
4/23/2018   12:27   4/23/2018 12:27
4/23/2018   19:29   4/23/2018 19:29
4/24/2018   1:08    4/24/2018 1:08
4/24/2018   5:24    4/24/2018 5:24
4/24/2018   9:44    4/24/2018 9:44
5/7/2018    9:48    5/7/2018 9:48
5/7/2018    17:59   5/7/2018 17:59
5/8/2018    0:55    5/8/2018 0:55
5/8/2018    1:00    5/8/2018 1:00
5/8/2018    4:30    5/8/2018 4:30
5/8/2018    9:41    5/8/2018 9:41
  

Я не уверен, что я излагаю свой вопрос понятным образом, поскольку эта логическая вещь сейчас портит мой мозг… Я был бы признателен за любые предложения и помощь! Кроме того, не стесняйтесь просить меня уточнить мой вопрос, если он недостаточно ясен.

Ответ №1:

Я бы использовал dplyr::between следующим образом.

Во-первых, давайте сгенерируем некоторые образцы данных (всегда лучше явно включать данные вместо предоставления ссылки).

 df <- data.frame(
    datetime = seq(
        as.POSIXct("2018-4-9 00:00"), as.POSIXct("2018-4-11 00:00"), by = "5 min"))
  

Затем мы можем фильтровать данные между "2018-4-9 9:45" и "2018-4-9 9:45" с помощью dplyr::between

 library(dplyr)
start <- as.POSIXct("2018-4-9 9:45")
end <- as.POSIXct("2018-4-10 9:45")
df %>% filter(between(datetime, start, end))
  

PS. Возможно, опечатка, но я думаю, что библиотека, на которую вы ссылаетесь в своем сообщении, называется lubridate , а не lubricate .


Обновить

Вы можете добиться фильтрации ваших исходных данных по нескольким (start, end) диапазонам, используя неравномерное объединение ваших исходных данных df и фрейма данных, который содержит разные диапазоны.

Вот пример, основанный на приведенных вами образцах данных и используемый fuzzyjoin::fuzzy_inner_join для выполнения неравновесного соединения:

 library(dplyr)
library(fuzzyjoin)
df_range <- data.frame(
    start = as.POSIXct(c("2018-4-9 9:45", "2018-4-23 9:45")),
    end = as.POSIXct(c("2018-4-10 9:45", "2018-4-24 9:45"))
)
df %>%
    fuzzy_inner_join(
        df_range, 
        by = c("datetime" = "start", "datetime" = "end"),
        match_fun = list(`>=`, `<=`)) %>%
    select(-start, -end)
#              datetime
#1  2018-04-09 10:00:00
#2  2018-04-09 11:00:00
#3  2018-04-09 12:00:00
#4  2018-04-09 13:00:00
#5  2018-04-09 14:00:00
#6  2018-04-09 15:00:00
#7  2018-04-09 16:00:00
#8  2018-04-09 17:00:00
#9  2018-04-09 18:00:00
#10 2018-04-09 19:00:00
#11 2018-04-09 20:00:00
#12 2018-04-09 21:00:00
#13 2018-04-09 22:00:00
#14 2018-04-09 23:00:00
#15 2018-04-10 00:00:00
#16 2018-04-23 10:00:00
#17 2018-04-23 11:00:00
#18 2018-04-23 12:00:00
#19 2018-04-23 13:00:00
#20 2018-04-23 14:00:00
#21 2018-04-23 15:00:00
#22 2018-04-23 16:00:00
#23 2018-04-23 17:00:00
#24 2018-04-23 18:00:00
#25 2018-04-23 19:00:00
#26 2018-04-23 20:00:00
#27 2018-04-23 21:00:00
#28 2018-04-23 22:00:00
#29 2018-04-23 23:00:00
#30 2018-04-24 00:00:00
  

Образец данных

 
df1 <- data.frame(
    datetime = seq(
        as.POSIXct("2018-4-9 00:00"), as.POSIXct("2018-4-10 00:00"), by = "60 min"))
df2 <- data.frame(
    datetime = seq(
        as.POSIXct("2018-4-23 00:00"), as.POSIXct("2018-4-24 00:00"), by = "60 min"))
df3 <- data.frame(
    datetime = seq(
        as.POSIXct("2018-5-7 00:00"), as.POSIXct("2018-5-8 00:00"), by = "60 min"))
df <- rbind(df1 , df2, df3)
  

Комментарии:

1. Привет @Maurits Evers, Поскольку у меня более 100 свиданий, есть ли способ сделать это за все эти дни? И спасибо вам за то, что указали на опечатку. Я изменил его.

2. @XM_Z «Поскольку у меня более 100 дат, есть ли способ сделать это со всеми этими днями?» Я не совсем понимаю, что ты имеешь в виду. Можете ли вы отредактировать свой пост, чтобы предоставить более минимальный пример, возможно, на основе примеров данных, которые я даю? Вы хотите отфильтровать исходные данные по нескольким (start, end) диапазонам? Если да, пожалуйста, уточните ваш ожидаемый результат.

3. Привет @Maurits Evers, я отредактировал свои вопросы в соответствии с рекомендациями. Да, я хотел бы отфильтровать свои исходные данные для более чем одного (начального, конечного) диапазона. У меня есть более 60 групп последовательных дат, и я хотел бы определить эти последовательные даты и отфильтровать период времени (с 9:45 утра первого дня до 9:45 утра следующего дня) среди каждой группы этих последовательных дат, например, 2018-4-9 ~ 2018-4-10, 2018-4-23 ~ 2018-4-24, …., 2020-6-5~2020-6-6.

4. Спасибо за обновление @XM_Z; Я думаю, что вам нужно неравнозначное соединение; Я внес правку в свой пост, пожалуйста, взгляните. Это должно быть легко обобщить для большего количества диапазонов.

5. Спасибо за обновление, @Maurits Evers! Я потрачу некоторое время на обработку данных, чтобы посмотреть, сработает ли это позже сегодня или завтра, и я дам вам знать.