bugfix> r > 投稿

計算する必要があります「いくつの x 離れたユニット」 POSIX日付のベクトルの各要素は、指定された参照日付からのものです。ここで、

  • x のような「典型的な」時間単位です週間四半期 等
  • 日付ベクトルは複数年にわたることができます
  • 結果は numeric である必要がありますベクター

私は何かを持っていますが、一般化できる一貫したアプローチのようには感じません(2つの異なるアプローチが  そして週間)。

おそらく何の価値もない:私は一般的に準拠するソリューションを探していますISO 8601

編集

「一貫性のある」という意味で、理想的には、常に as.numeric(dates) を活用するソリューションを言うその後、いくつかの巧妙な「時間単位ビニング」を行います。しかし、ヶ月 各月には異なる日数が含まれているため、これがどのように達成されるかわかりません(常に安全に「1週間に7日間」と言うことができるため、数週間は機能します)。

言い換えれば:ヶ月  (as.numeric(.x) / (<something>)) のようなものを使用したい (as.numeric(.x) / (60 * 60 * 24 * 7)) を使用するようににとって週間。それは <something>  日付の違いをビニングする一般的な方法を探しています。

ソリューションドラフト

関数の定義:

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に作成されたreprexパッケージ (v0.2.0)。

回答 2 件
  • 1つのオプションは、式を引数として渡してから解析することです

    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
    
    

  • 1日の倍数である間隔に関心がある場合は、POSIXtクラスを使用しても意味がありません。 Dateクラスを使用することで完全に防止できるタイムゾーンエラーの可能性が生じるだけなので、以降はDateクラスを想定します。 as.Dateは、POSIXctオブジェクトをDateオブジェクトに変換するために使用できます。

    質問には2つの異なるケースがあります。 1日の倍数である間隔(日、週)および1か月の倍数である間隔(月、四半期、年)。 1か月の日数は固定されていないため、これらは個別に処理する必要があります。

    ケース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です。

    編集

    修正(2)。

あなたの答え