Различия в разбивке по датам в виде числового вектора с учетом единиц времени - PullRequest
0 голосов
/ 25 мая 2018

Мне нужно вычислить "сколько x единиц измерения" каждый элемент в векторе дат POSIX взят из заданной контрольной даты, где

  • x"типичная" единица времени, такая как месяц , неделя , квартал и т. д.
  • вектор даты может охватывать несколько лет
  • результат должен быть numeric вектор

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

Возможно, ничего не стоит: я обычно ищу решения, соответствующие ISO 8601

EDIT

«Последовательный» в том смысле, что в идеале я бы сказал, скажем, решение, которое всегда использует as.numeric(dates) с каким-то умным «объединением единиц времени» впоследствии.Но для месяцев я бы не увидел, как этого можно достичь, поскольку каждый месяц содержит разное количество дней (работает неделями, поскольку мы всегда можем с уверенностью сказать, что "неделя содержит 7 дней").

Другими словами: для месяцев Я бы хотел использовать что-то вроде (as.numeric(.x) / (<something>)), как я использую (as.numeric(.x) / (60 * 60 * 24 * 7)) для недель .Это то, что <something>, который я ищу, чтобы иметь общий способ разбивки различий в датах.

черновик решения

Функция defs:

library(magrittr)
library(purrr)

normalize_time_distance_month <- function(dates) {
  dates %>%
    as.POSIXct() %>%
    purrr::map_dbl(function(.x)
      as.numeric(format(.x, "%y")) * 12 + as.numeric(format(.x, "%m")))
}

normalize_time_distance_week <- function(dates) {
  dates %>%
    as.POSIXct() %>%
    purrr::map_dbl(function(.x)
      (as.numeric(.x) / (60 * 60 * 24 * 7)) %>%
        round())
}

Месяцы:

# Months ------------------------------------------------------------------

dates <- seq(as.POSIXct("2018-03-01"), length.out = 24, by = "month")
origin <- as.POSIXct("2018-05-01")

dates_norm <- normalize_time_distance_month(dates)
origin_norm <- normalize_time_distance_month(origin)

(time_diffs <- dates_norm - origin_norm)
#>  [1] -2 -1  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
#> [24] 21

Недели:

# Weeks -------------------------------------------------------------------

dates <- seq(as.POSIXct("2018-05-07"), length.out = 104, by = "week")
origin <- as.POSIXct("2018-05-21")

dates_norm <- normalize_time_distance_week(dates)
origin_norm <- normalize_time_distance_week(origin)

(time_diffs <- dates_norm - origin_norm)
#>   [1]  -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14
#>  [18]  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
#>  [35]  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48
#>  [52]  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65
#>  [69]  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82
#>  [86]  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99
#> [103] 100 101

Создано в 2018-05-25 пакетом Представить (v0.2.0).

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Если вас интересуют интервалы, кратные дню, нет смысла использовать класс POSIXt.Это только приведет к возможности возникновения ошибок часового пояса, которые вы можете полностью предотвратить с помощью класса Date, поэтому мы будем использовать класс Date.as.Date можно использовать для преобразования объекта POSIXct в объект Date.

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

Случай 1 - интервал, кратный дням

Если длина интервала составляет d дней, то еслиx и y - объекты класса Date, число интервалов составляет

# x and y are Date class
(as.numeric(y) - as.numeric(x)) / d

, где d равно 1 для дней и 7 для недель.

Случай 2 - интервал, кратный месяцу

Если длина интервала составляет m месяцев, то если x и y являются объектами класса Date:

library(zoo)

date2ym <- function(x) {
   ym <- as.yearmon(x)
   b <- as.numeric(as.Date(ym))
   e <- as.numeric(as.Date(ym, frac = 1))
   12 * as.numeric(ym) + (as.numeric(x) - b) / (e - b + 1)
}

# x and y are Date class
(date2ym(y) - date2ym(x)) / m 

, где m равно 1 для месяцев, 3 для кварталов и 12 для лет.

РЕДАКТИРОВАТЬ

Fix (2).

0 голосов
/ 25 мая 2018

Один из вариантов - передать выражение в качестве аргумента, а затем проанализировать его

library(tidyverse)
library(rlang)
normalize_time_distance <- function(dates, expr) {
 dates %>%
    as_tibble %>% 
    mutate(value = as.POSIXct(value)) %>%
    mutate(value = !! parse_expr(expr)) %>%
    pull(value)

 }

expr1 <- 'as.numeric(format(value, "%y")) * 12 + as.numeric(format(value, "%m"))'
normalize_time_distance(dates, expr1)
#[1] 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
#[20] 238 239 240 241 242



expr2 <-  'round((as.numeric(value) / (60 * 60 * 24 * 7)))'
normalize_time_distance(dates, expr2)
#[1] 2513 2517 2522 2526 2530 2535 2539 2544 2548 2552 2557 2561 2565 2570 2574
#[16] 2578 2583 2587 2591 2596 2600 2604 2609 2613
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...