思っちゃったんだからしょうがない

統計学を学ぶ傍でひっそりとやっていきます。 #statistics #R

定期的なイベントを年月日でいい感じに扱うパッケージ almanac

この記事は何?

本記事はRのパッケージ almanac パッケージの紹介です。こちらのGithubに記載してある内容を試した記事になります。 ※一部間違っており修正しました。

davisvaughan.github.io

モチベーション

10月の第2月曜日は何の日でしょう。そう、スポーツの日です。

では、過去10年間のスポーツの日の日付はいつでしたか。と聞かれると一手間かかりますが、そんな一手間を解消してくれそうなパッケージを見つけたので試してみつつ紹介記事を書きます。

 

インストール

remotesパッケージをあらかじめインストールしてください。 vctrsgithubにある物をインストールしてください。

remotes::install_github("DavisVaughan/almanac")

MacWindowsユーザーは問題ないですが、Linuxユーザーの方は上記のページを参照ください。

例:定期的な予定を扱う

例として、thanksgivingが挙げられています。ここでは、11月の第4金曜日というルールのオブジェクトを作っています。

# Thanksgiving = "The fourth Thursday in November"
on_thanksgiving <- yearly() %>%
  recur_on_ymonth("November") %>%
  recur_on_wday("Thursday", nth = 4)

on_thanksgiving
> <rrule[yearly / 1970-01-01 / 2040-01-01]>
> - ymonth: Nov
> - wday: Thu[4]

ルールオブジェクトを生成できたら、これから実際に日付を生成できます。

alma_search("2000-01-01", "2006-12-31", on_thanksgiving)
[1] "2000-11-23" "2001-11-22" "2002-11-28" "2003-11-27" "2004-11-25" "2005-11-24" "2006-11-23"

また、日付に対してルールに該当するかの判定もすることができます。

# Is this a Thanksgiving?
alma_in(c("2000-01-01", "2000-11-23"), on_thanksgiving)
#> [1] FALSE  TRUE

ルールに該当する日を飛ばした日付計算をすることもできます。 2000年は11月23日がthanksgivingでしたが、 11月22日と23日で23日を飛ばした場合の2日後は同じになるという雰囲気です。

step_over_thanksgiving <- stepper(on_thanksgiving)
base_date <- as.Date("2000-11-22")
base_date %s+% step_over_thanksgiving(2)
"2000-11-25"

base_date <- as.Date("2000-11-23")
base_date %s+% step_over_thanksgiving(2)
"2000-11-25"

発展

複数のルールをまとめて扱うこともできる。その場合は、個別のルールーをバンドルしたオブジェクトを作って扱う必要がある。

# 毎週末のルール
on_weekends <- weekly() %>%
  recur_on_weekends()

# クリスマスのルール
on_christmas <- yearly() %>%
  recur_on_mday(25) %>%
  recur_on_ymonth("Dec")

# thanksgivingと週末とクリスマスのルールをまとめたルールを作る
bundle <- rbundle() %>%
  add_rschedule(on_weekends) %>%
  add_rschedule(on_christmas) %>%
  add_rschedule(on_thanksgiving)

日本の出勤日のルールを作ってみる

手を抜いて祝日を除く出勤日ではない日をまとめると、

  • 週末
  • 年末年始(12/28-1/3)
#-----------------------------
on_yearends <- rbundle() %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Dec") %>% 
      recur_on_mday(28)
  ) %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Dec") %>% 
      recur_on_mday(29)
  ) %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Dec") %>% 
      recur_on_mday(30)
  ) %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Dec") %>% 
      recur_on_mday(31)
  )

#-----------------------------
on_yearstarts <- rbundle() %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Jan") %>% 
      recur_on_mday(1)
  ) %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Jan") %>% 
      recur_on_mday(2)
  ) %>% 
  add_rschedule(
    yearly() %>% 
      recur_on_ymonth("Jan") %>% 
      recur_on_mday(3)
  )

#---------------------------
on_japanese_weekday <- rbundle() %>% 
  add_rschedule(on_yearends) %>% 
  add_rschedule(on_yearstarts)

library(stringr)
date_list <- seq(as.Date('2020-01-01'), as.Date('2020-12-31'), 1)

!alma_in(date_list, on_japanese_weekday)

※上記のコードが"Feb"になっていたのを"Jan"に修正しました。

  [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [18]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [35]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [52]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [69]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [86]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[103]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[120]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[137]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[154]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[171]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[188]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[205]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[222]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[239]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[256]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[273]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[290]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[307]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[324]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[341]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
[358]  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE

結構便利かも。

以上、さくっと紹介でした。