ダミー変数を生成するgemを作ってみた

dummy_variables

時系列分析をする際に、量的データ以外の事項を考慮に入れたい場合があります。 例えば、商品の売上推移をモデリングするために、価格などの数値以外にも、曜日の影響を取り入れたい場合です。曜日は数値ではないので、何らかの形で数値化する必要があります。通常はダミー変数を使うことになります。つまり、土曜日なら「1」、それ以外なら「0」のような変数を用意します。

このようなダミー変数の生成を簡単にできるようにしたい、ということで、Rubyでdummy_variablesというライブラリを作り、Gemにしました。公式ドキュメントに書き忘れましたが(そのうち追記します)、Ruby2.0以上でないとダメなはずです(実装にキーワード引数を使っていますが、キーワード引数は2.0で追加された仕様なので)。

https://github.com/aknd/dummy_variables

インストール

$ gem install dummy_variablesとしても良いですが、 bundlerはインストールされている前提で、Gemfileに

gem 'dummy_variables'

と書いて

$ bundle install --path vendor/bundle

のようにするのがオススメです。

使用方法

requireしておいて、

require "dummy_variables"

DummyVariables::Calendar.newの引数に開始日と終了日を渡します。 to_csv_strで、CSV形式の文字列を出力するので、それをファイルに書き込みます。

cal = DummyVariables::Calendar.new("20140101", "20151231")
File.open("cal.csv", "w") { |file| file.write(cal.to_csv_str) }

中身を見てみると、デフォルトで曜日が全てダミー変数になっています。

date,sun,mon,tue,wed,thu,fri,sat
2014-01-01,0,0,0,1,0,0,0
2014-01-02,0,0,0,0,1,0,0
2014-01-03,0,0,0,0,0,1,0
2014-01-04,0,0,0,0,0,0,1
2014-01-05,1,0,0,0,0,0,0
2014-01-06,0,1,0,0,0,0,0
2014-01-07,0,0,1,0,0,0,0
2014-01-08,0,0,0,1,0,0,0
2014-01-09,0,0,0,0,1,0,0

日付のフォーマットを指定したり、出力するカラムを選択したり、ヘッダーの有無やダブルクォーテーションの有無などのオプションを指定したりできます。

cal = DummyVariables::Calendar.new("20140101", "20151231", "%Y/%m/%d") # add date format

File.open("cal.csv", "w") do |file|
  file.write(
    cal.to_csv_str(
      [:sat, :sun], # select columns
      options: { # add options
        :write_headers => false,
        :force_quotes => true
      }
    )
  )
end

中身を確認。

"2014/01/01","0","0"
"2014/01/02","0","0"
"2014/01/03","0","0"
"2014/01/04","1","0"
"2014/01/05","0","1"
"2014/01/06","0","0"
"2014/01/07","0","0"
"2014/01/08","0","0"
"2014/01/09","0","0"
"2014/01/10","0","0"

曜日以外のダミー変数を生成するためには、設定ファイルを作ります。 YAMLかJSONですが、今回はYAMLにして、config_file.ymlというファイル名で作成します。

holiday:
  dates:
    - 2014-01-01
    - 2014-01-13
    - 2014-02-11
    - 2014-03-21
    - 2014-04-29
    - 2014-05-03
    - 2014-05-04
    - 2014-05-05
    - 2014-05-06
    - 2014-07-21
    - 2014-09-15
    - 2014-09-23
    - 2014-10-13
    - 2014-11-03
    - 2014-11-23
    - 2014-11-24
    - 2014-12-23
    - 2015-01-01
    - 2015-01-12
    - 2015-02-11
    - 2015-03-21
    - 2015-04-29
    - 2015-05-03
    - 2015-05-04
    - 2015-05-05
    - 2015-05-06
    - 2015-07-20
    - 2015-09-21
    - 2015-09-22
    - 2015-09-23
    - 2015-10-12
    - 2015-11-03
    - 2015-11-23
    - 2015-12-23
break:
  dates:
    - 2014-01-02
    - 2014-01-03
    - 2014-08-13
    - 2014-08-14
    - 2014-08-15
    - 2014-12-29
    - 2014-12-30
    - 2014-12-31
    - 2015-01-02
    - 2015-08-13
    - 2015-08-14
    - 2015-12-29
    - 2015-12-30
    - 2015-12-31

設定ファイル名config_file.ymlを引数に渡します。config_file: とキーワードを指定する必要があるので注意してください。

cal = DummyVariables::Calendar.new("20140101", "20151231", config_file: "config_file.yml")
File.open("cal.csv", "w") { |file| file.write(cal.to_csv_str) }

中身を確認すると、設定ファイルに書いたholiday(祝日)とbreak(年末年始など、祝日以外の長期休暇)がダミー変数になっています。

date,sun,mon,tue,wed,thu,fri,sat,holiday,break
2014-01-01,0,0,0,1,0,0,0,1,0
2014-01-02,0,0,0,0,1,0,0,0,1
2014-01-03,0,0,0,0,0,1,0,0,1
2014-01-04,0,0,0,0,0,0,1,0,0
2014-01-05,1,0,0,0,0,0,0,0,0
2014-01-06,0,1,0,0,0,0,0,0,0
2014-01-07,0,0,1,0,0,0,0,0,0
2014-01-08,0,0,0,1,0,0,0,0,0
2014-01-09,0,0,0,0,1,0,0,0,0

設定ファイルを用意するのではなく、設定データを引数で直接渡すこともできます。

config_data = {
  "holiday" => {
    "dates" => [
      "2014-01-01", "2014-01-13", "2014-02-11", "2014-03-21", "2014-04-29", "2014-05-03", "2014-05-04",
      "2014-05-05", "2014-05-06", "2014-07-21", "2014-09-15", "2014-09-23", "2014-10-13", "2014-11-03",
      "2014-11-23", "2014-11-24", "2014-12-23", "2015-01-01", "2015-01-12", "2015-02-11", "2015-03-21",
      "2015-04-29", "2015-05-03", "2015-05-04", "2015-05-05", "2015-05-06", "2015-07-20", "2015-09-21",
      "2015-09-22", "2015-09-23", "2015-10-12", "2015-11-03", "2015-11-23", "2015-12-23"
    ]
  },
  "break" => {
    "dates" => [
      "2014-01-02", "2014-01-03", "2014-08-13", "2014-08-14", "2014-08-15", "2014-12-29", "2014-12-30",
      "2014-12-31", "2015-01-02", "2015-08-13", "2015-08-14", "2015-12-29", "2015-12-30", "2015-12-31"
    ]
  }
}

cal = DummyVariables::Calendar.new("20140101", "20151231", config_data: config_data)
File.open("cal.csv", "w") { |file| file.write(cal.to_csv_str) }

さっきと同様に上手くいきました。

date,sun,mon,tue,wed,thu,fri,sat,holiday,break
2014-01-01,0,0,0,1,0,0,0,1,0
2014-01-02,0,0,0,0,1,0,0,0,1
2014-01-03,0,0,0,0,0,1,0,0,1
2014-01-04,0,0,0,0,0,0,1,0,0
2014-01-05,1,0,0,0,0,0,0,0,0
2014-01-06,0,1,0,0,0,0,0,0,0
2014-01-07,0,0,1,0,0,0,0,0,0
2014-01-08,0,0,0,1,0,0,0,0,0
2014-01-09,0,0,0,0,1,0,0,0,0