日付の途中を補完するtidyr::complete()関数
時系列データでよく使うので備忘録。
まずtidyr::complete()関数の使い方から。
組み合わせの欠損を埋めてくれる関数。
Complete a data frame with missing combinations of data — complete • tidyr
メモ:時系列とか連番のデータを補完するときはtidyrのcomplete()とfull_seq()が便利そう - Technically, technophobic.
サンプルデータを作成する。idが”111”と”222”のデータがあるが、それぞれyear_monthの途中が欠けている。
id“111”は3,5月、”222”は2,3月のレコードが無い。
df_1 <- tibble::tribble( ~id, ~year_month, ~cnt, "111", "2022-01-01", 1, "111", "2022-02-01", 2, "111", "2022-04-01", 4, "222", "2022-01-01", 1, "222", "2022-04-01", 4, "222", "2022-05-01", 5, ) |> dplyr::mutate(year_month = as.Date(year_month))
seq.Date()関数とtidyr::complete()関数を組み合わせると、補完することができる。
df_1 |> tidyr::complete(id, year_month = seq.Date(as.Date(min(year_month, na.rm = TRUE)), as.Date(max(year_month, na.rm = TRUE)), by = "months")) # A tibble: 10 × 3 # id year_month cnt # <chr> <date> <dbl> # 1 111 2022-01-01 1 # 2 111 2022-02-01 2 # 3 111 2022-03-01 NA # 4 111 2022-04-01 4 # 5 111 2022-05-01 NA # 6 222 2022-01-01 1 # 7 222 2022-02-01 NA # 8 222 2022-03-01 NA # 9 222 2022-04-01 4 # 10 222 2022-05-01 5
ここから気になって調べたところ。
seq.Date()関数の始まりと終わりの日付に、元のデータに存在しないものを指定しても、指定した範囲で補完してくれる。
例えば元のサンプルデータには2022年1月から2022年5月までしか存在しないが、seq.Date()関数に2021年12月から2022年6月まで指定すると次のように返ってくる。
df_1 |> tidyr::complete(id, year_month = seq.Date(as.Date("2021-12-01"), as.Date("2022-06-01"), by = "months")) # A tibble: 14 × 3 # id year_month cnt # <chr> <date> <dbl> # 1 111 2021-12-01 NA # 2 111 2022-01-01 1 # 3 111 2022-02-01 2 # 4 111 2022-03-01 NA # 5 111 2022-04-01 4 # 6 111 2022-05-01 NA # 7 111 2022-06-01 NA # 8 222 2021-12-01 NA # 9 222 2022-01-01 1 # 10 222 2022-02-01 NA # 11 222 2022-03-01 NA # 12 222 2022-04-01 4 # 13 222 2022-05-01 5 # 14 222 2022-06-01 NA
完全に範囲外の1900年の日付を指定すると、その範囲だけ組み合わせが発生する。
元々存在していた2022年のレコードは変わらず。
df_1 |> tidyr::complete(id, year_month = seq.Date(as.Date("1900-01-01"), as.Date("1900-02-01"), by = "months")) # A tibble: 10 × 3 # id year_month cnt # <chr> <date> <dbl> # 1 111 1900-01-01 NA # 2 111 1900-02-01 NA # 3 222 1900-01-01 NA # 4 222 1900-02-01 NA # 5 111 2022-01-01 1 # 6 111 2022-02-01 2 # 7 111 2022-04-01 4 # 8 222 2022-01-01 1 # 9 222 2022-04-01 4 # 10 222 2022-05-01 5
次に、idとは別に、idに対して紐づいている変数を持っている場合。
サンプルデータとして、各idにnameがあるデータを作成する。
df_2 <- tibble::tribble( ~id, ~name, ~year_month, ~cnt, "111", "xxx", "2022-01-01", 1, "111", "xxx", "2022-02-01", 2, "111", "xxx", "2022-04-01", 4, "222", "yyy", "2022-01-01", 1, "222", "yyy" ,"2022-04-01", 4, "222", "yyy", "2022-05-01", 5, ) |> dplyr::mutate(year_month = as.Date(year_month))
これをそのままtidyr::complete()に放り込むと、idとnameを含めて、すべての組み合わせが作成される。
df_2 |> tidyr::complete(id, name, year_month = seq.Date(as.Date(min(year_month, na.rm = TRUE)), as.Date(max(year_month, na.rm = TRUE)), by = "months")) # A tibble: 20 × 4 # id name year_month cnt # <chr> <chr> <date> <dbl> # 1 111 xxx 2022-01-01 1 # 2 111 xxx 2022-02-01 2 # 3 111 xxx 2022-03-01 NA # 4 111 xxx 2022-04-01 4 # 5 111 xxx 2022-05-01 NA # 6 111 yyy 2022-01-01 NA # 7 111 yyy 2022-02-01 NA # 8 111 yyy 2022-03-01 NA # 9 111 yyy 2022-04-01 NA # 10 111 yyy 2022-05-01 NA # 11 222 xxx 2022-01-01 NA # 12 222 xxx 2022-02-01 NA # 13 222 xxx 2022-03-01 NA # 14 222 xxx 2022-04-01 NA # 15 222 xxx 2022-05-01 NA # 16 222 yyy 2022-01-01 1 # 17 222 yyy 2022-02-01 NA # 18 222 yyy 2022-03-01 NA # 19 222 yyy 2022-04-01 4 # 20 222 yyy 2022-05-01 5
idとnameの組み合わせは動かしたくない場合は、tidyr::nesting()関数で囲って渡す。
df_2 |> tidyr::complete(tidyr::nesting(id, name), year_month = seq.Date(as.Date(min(year_month, na.rm = TRUE)), as.Date(max(year_month, na.rm = TRUE)), by = "months")) # A tibble: 10 × 4 # id name year_month cnt # <chr> <chr> <date> <dbl> # 1 111 xxx 2022-01-01 1 # 2 111 xxx 2022-02-01 2 # 3 111 xxx 2022-03-01 NA # 4 111 xxx 2022-04-01 4 # 5 111 xxx 2022-05-01 NA # 6 222 yyy 2022-01-01 1 # 7 222 yyy 2022-02-01 NA # 8 222 yyy 2022-03-01 NA # 9 222 yyy 2022-04-01 4 # 10 222 yyy 2022-05-01 5