Сгенерируйте последовательность дат для заданной частоты в соответствии с днями возникновения

#r #datetime #dplyr #lubridate

Вопрос:

Попытка сгенерировать последовательность дат в программировании R (с использованием lubridate) дат с заданной датой начала и частотой-это не числовое значение, а дни, в которые могут произойти даты.

Ниже приведена таблица, в которой определены группа, дата начала, день и флаг события

  ------- ------------ ----- ----- 
| Group | start_date | Day | Y/N |
 ------- ------------ ----- ----- 
| foo   | 02-06-2021 | Mon |   0 |
| foo   | 02-06-2021 | Tue |   1 |
| foo   | 02-06-2021 | Wed |   0 |
| foo   | 02-06-2021 | Thu |   1 |
| foo   | 02-06-2021 | Fri |   1 |
| foo   | 02-06-2021 | Sat |   1 |
| foo   | 02-06-2021 | Sun |   0 |
| bar   | 02-06-2021 | Mon |   1 |
| bar   | 02-06-2021 | Tue |   0 |
| bar   | 02-06-2021 | Wed |   0 |
| bar   | 02-06-2021 | Thu |   1 |
| bar   | 02-06-2021 | Fri |   1 |
| bar   | 02-06-2021 | Sat |   0 |
| bar   | 02-06-2021 | Sun |   0 |
 ------- ------------ ----- ----- 
 

Требуемая производительность, как показано ниже.

  ------- ------------ --------------------- 
| Group | given_date | next_available_date |
 ------- ------------ --------------------- 
| foo   | 02-06-2021 | 03-06-2021          |
| foo   | 04-06-2021 | 04-06-2021          |
| foo   | 06-06-2021 | 08-06-2021          |
| bar   | 02-06-2021 | 03-06-2021          |
| bar   | 05-06-2021 | 07-06-2021          |
 ------- ------------ --------------------- 
 

Некоторые идеи вокруг цикла while, которые, как я думал, могут быть утомительными.

 for each given_date{
inputdate = given_date
while(true){
 {
 if(group =="Foo" amp; day(inputdate) in ('Tue','Thu','Fri','Sat')
 next_available_date=inputdate
 break
 }
 else
 {
  inputdate = inputdate (1 day) (repeat the loop until if condition is satisfied)
 } 
}
}
 

Если условия для разных групп могут быть разными.

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

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

1. Можете ли вы объяснить результат? Что же Day представляет собой? Что такое Y/N ? Также, как вы вычисляете given_date и next_available_date ?

2. Y/N-это основа флага, на которой мы определим, может ли произойти дата или нет, например : для foo и заданной даты 02-06-2021, которая является средой, следующая доступная дата не может быть ср, потому что столбец Y/N имеет 0 против Ср, следующая доступная дата тогда будет 03-06-2021, что Чт и Y/N = 1, тот же случай будет применяться для бара 05-06-2021, который сб, но с флага Y/N и сб и вс 0,0 соответственно, следовательно, следующая доступная дата будет приходиться на 07-06-2021

3. Извините, если я не совсем ясно выражаюсь, новичок в stackoverflow

4. Да дата начала останется прежней для группы

5. Конечно, сделаю это

Ответ №1:

Работа над более крупной выборкой, как обсуждалось ранее в комментариях. Последовала стратегия —

  • Поскольку ваш day столбец всегда начинается с Mon того, что не равно start_date , поэтому требуется сопоставление столбцов weekday .
  • Таким образом, создано day поле упорядоченного factor типа, чтобы им можно было манипулировать, превращая его в целые числа.
  • Расположите фрейм данных таким образом, чтобы каждая ваша группа начиналась только с этого дня. Для этого используется деление %% по модулю
  • После организации задача стала несколько проще. Я создал семь дат для каждого конца рабочего дня, для каждой группы и для каждой даты начала.
  • Отфильтрованные строки с Y/N 0 в любом месте.
  • Теперь вам требуется только верхний ряд, поэтому используется slice_head()
 df <- data.frame(
  stringsAsFactors = FALSE,
                   Group = c("foo","foo","foo",
                             "foo","foo","foo","foo","foo","foo","foo",
                             "foo","foo","foo","foo","foo","foo","foo",
                             "foo","foo","foo","foo","bar","bar","bar",
                             "bar","bar","bar","bar","bar","bar","bar","bar",
                             "bar","bar","bar"),
              start_date = c("02-06-2021",
                             "02-06-2021","02-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","02-06-2021","04-06-2021",
                             "04-06-2021","04-06-2021","04-06-2021","04-06-2021",
                             "04-06-2021","04-06-2021","06-06-2021","06-06-2021",
                             "06-06-2021","06-06-2021","06-06-2021",
                             "06-06-2021","06-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","02-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","05-06-2021","05-06-2021",
                             "05-06-2021","05-06-2021","05-06-2021","05-06-2021",
                             "05-06-2021"),
                     Day = c("Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun","Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun","Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun","Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun","Mon","Tue","Wed","Thu",
                             "Fri","Sat","Sun"),
                     y_n = c(0L,1L,0L,1L,1L,
                             1L,0L,0L,1L,0L,1L,1L,1L,0L,0L,1L,0L,1L,
                             1L,1L,0L,1L,0L,0L,1L,1L,0L,0L,1L,0L,
                             0L,1L,1L,0L,0L)
      )

library(lubridate)
library(tidyverse)

df %>% group_by(Group, start_date) %>%
  mutate(Day = factor(Day, levels = Day, ordered = T)) %>%
  arrange(Group, (as.numeric(Day)   7 - wday(dmy(start_date), week_start = 1)) %% 7, .by_group = T) %>%
  mutate(next_available_date = dmy(start_date)   0:6) %>%
  filter(y_n !=0) %>%
  slice_head()
#> # A tibble: 5 x 5
#> # Groups:   Group, start_date [5]
#>   Group start_date Day     y_n next_available_date
#>   <chr> <chr>      <ord> <int> <date>             
#> 1 bar   02-06-2021 Thu       1 2021-06-03         
#> 2 bar   05-06-2021 Mon       1 2021-06-07         
#> 3 foo   02-06-2021 Thu       1 2021-06-03         
#> 4 foo   04-06-2021 Fri       1 2021-06-04         
#> 5 foo   06-06-2021 Tue       1 2021-06-08
 

На основании предоставленных данных

 df <- data.frame(
  stringsAsFactors = FALSE,
                   Group = c("foo","foo","foo",
                             "foo","foo","foo","foo","bar","bar","bar",
                             "bar","bar","bar","bar"),
              start_date = c("02-06-2021",
                             "02-06-2021","02-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","02-06-2021","02-06-2021","02-06-2021",
                             "02-06-2021","02-06-2021"),
                     Day = c("Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun","Mon","Tue","Wed",
                             "Thu","Fri","Sat","Sun"),
                     y_n = c(0L,1L,0L,1L,1L,
                             1L,0L,1L,0L,0L,1L,1L,0L,0L)
      )

library(lubridate)
library(tidyverse)



df %>% group_by(Group, start_date) %>%
  mutate(Day = factor(Day, levels = Day, ordered = T)) %>%
  arrange(Group, (as.numeric(Day)   7 - wday(dmy(start_date), week_start = 1)) %% 7, .by_group = T) %>%
  mutate(next_available_date = dmy(start_date)   0:6) %>%
  filter(y_n !=0) %>%
  slice_head()

#> # A tibble: 2 x 5
#> # Groups:   Group, start_date [2]
#>   Group start_date Day     y_n next_available_date
#>   <chr> <chr>      <ord> <int> <date>             
#> 1 bar   02-06-2021 Thu       1 2021-06-03         
#> 2 foo   02-06-2021 Thu       1 2021-06-03
 

Создано 2021-06-02 пакетом reprex (v2.0.0)

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

1. Не уверен, как работает код, если вы дадите краткое объяснение, я изучу его дальше