Статьи

R: Время в / из выходных

В моем последнем посте я показал несколько примеров использования пакета lubridate от R, и еще одной проблемой, которую было действительно легко решить, было выяснение того, насколько близко определенное время было к выходным.

Я хотел написать функцию, которая возвращала бы предыдущее воскресенье или предстоящую субботу, в зависимости от того, что было ближе.

Функции lubridate floor_date и terrace_date делают это довольно просто.

Например, если мы хотим округлить 18 декабря до начала недели и до начала следующей недели, мы можем сделать следующее:

1
2
3
4
5
6
> library(lubridate)
> floor_date(ymd("2014-12-18"), "week")
[1] "2014-12-14 UTC"
  
> ceiling_date(ymd("2014-12-18"), "week")
[1] "2014-12-21 UTC"

Для даты в будущем мы на самом деле хотим взять субботу, а не воскресенье, поэтому мы вычтем один день из этого:

1
2
> ceiling_date(ymd("2014-12-18"), "week") - days(1)
[1] "2014-12-20 UTC"

Теперь давайте соберем это вместе в функцию, которая находит ближайшие выходные для данной даты:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
findClosestWeekendDay = function(dateToLookup) {
  before = floor_date(dateToLookup, "week") + hours(23) + minutes(59) + seconds(59)
  after  = ceiling_date(dateToLookup, "week") - days(1)
  if((dateToLookup - before) < (after - dateToLookup)) {
    before 
  } else {
    after 
  }
}
  
> findClosestWeekendDay(ymd_hms("2014-12-13 13:33:29"))
[1] "2014-12-13 UTC"
  
> findClosestWeekendDay(ymd_hms("2014-12-14 18:33:29"))
[1] "2014-12-14 23:59:59 UTC"
  
> findClosestWeekendDay(ymd_hms("2014-12-15 18:33:29"))
[1] "2014-12-14 23:59:59 UTC"
  
> findClosestWeekendDay(ymd_hms("2014-12-17 11:33:29"))
[1] "2014-12-14 23:59:59 UTC"
  
> findClosestWeekendDay(ymd_hms("2014-12-17 13:33:29"))
[1] "2014-12-20 UTC"
  
> findClosestWeekendDay(ymd_hms("2014-12-19 13:33:29"))
[1] "2014-12-20 UTC"

Я установил воскресную дату в 23:59:59, чтобы я мог использовать эту дату на следующем шаге, где мы хотим вычислить, сколько часов это от текущей даты до ближайших выходных.

Я закончил с этой функцией:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
distanceFromWeekend = function(dateToLookup) {
  before = floor_date(dateToLookup, "week") + hours(23) + minutes(59) + seconds(59)
  after  = ceiling_date(dateToLookup, "week") - days(1)
  timeToBefore = dateToLookup - before
  timeToAfter = after - dateToLookup
  
  if(timeToBefore < 0 || timeToAfter < 0) {
    0 
  } else {
    if(timeToBefore < timeToAfter) {
      timeToBefore / dhours(1)
    } else {
      timeToAfter / dhours(1)
    }
  }
}
  
> distanceFromWeekend(ymd_hms("2014-12-13 13:33:29"))
[1] 0
  
> distanceFromWeekend(ymd_hms("2014-12-14 18:33:29"))
[1] 0
  
> distanceFromWeekend(ymd_hms("2014-12-15 18:33:29"))
[1] 18.55833
  
> distanceFromWeekend(ymd_hms("2014-12-17 11:33:29"))
[1] 59.55833
  
> distanceFromWeekend(ymd_hms("2014-12-17 13:33:29"))
[1] 58.44194
  
> distanceFromWeekend(ymd_hms("2014-12-19 13:33:29"))
[1] 10.44194

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

Должен быть умный R способ сделать то же самое (возможно, с использованием матриц), который я еще не понял, так что, если вы знаете, как ускорить это, дайте мне знать.

Ссылка: R: Время в / из выходных от нашего партнера JCG Марка Нидхэма в блоге Марка Нидхэма