洋食の日記

「だ・である」調ではなく「です・ます」調で書きはじめれば良かったなと後悔してる人のブログです

Rumaleにスタッキングによる分類器と回帰分析を追加した

はじめに

Ruby機械学習ライブラリであるRumaleに、スタッキング(stacking / stacked generalization)を用いた分類器と回帰分析を追加して、ver. 0.22.2としてリリースした。

rumale | RubyGems.org | your community gem host

使い方

Rumaleはgemコマンドでインストールできる。

$ gem install rumale

今回は高速化のためにparallelとnumo-openblasもインストールする(必須ではない)。

$ gem install parallel numo-openblas

スタッキングは、アンサンブル手法の一種で、一般的に学習器を二段階構成でつなげる。複数の学習器(first-level learner)を訓練し、それらの推定結果を特徴量として、最終的な推定をおこなう学習器(second-level learner / meta-leaner)を訓練する。これを実装しようとすると、割と大変というか、コードが冗長なものになる。そこで、専用のものを作った(scikit-learnでも ver. 0.22 で追加された)。

回帰分析を例に使ってみる。まずは、ランダム森による回帰分析を試す。データセットにはLIBSVM Dataのabaloneを用いた。

$ wget https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/regression/abalone_scale
require 'numo/openblas'
require 'parallel'
require 'rumale'

# データセットを読み込む.
x, y = Rumale::Dataset.load_libsvm_file('abalone_scale')

# 訓練とテストに分割する.
x_train, x_test, y_train, y_test = Rumale::ModelSelection.train_test_split(x, y, test_size: 0.2, random_seed: 1)

# ランダム森を学習する.
reg = Rumale::Ensemble::RandomForestRegressor.new(n_jobs: -1, random_seed: 1)
reg.fit(x_train, y_train)

# 決定係数 (1に近づくほどよい) により回帰の精度を評価する.
puts reg.score(x_test, y_test)

これを実行すると、以下のようになる。

$ ruby regression.rb
R2-Score: 0.5224

これがスタッキングにより、どれだけスコアが向上するか試してみる。ランダム森による回帰を、以下のスタッキングに置き換える。一段目の学習機の種類やハイパーパラメータは適当なものである。

# ランダム森のところをスタッキングに置き換える.
# estimatorsにHashで特徴抽出に使う一段目の推定器を指定する.
# meta_estimatorに実際に推定結果を返す二段目の推定器を指定する.
reg = Rumale::Ensemble::StackingRegressor.new(
  estimators: {
    rnd: Rumale::Ensemble::RandomForestRegressor.new(n_jobs: -1, random_seed: 1),
    ext: Rumale::Ensemble::ExtraTreesRegressor.new(n_jobs: -1, random_seed: 1),
    grd: Rumale::Ensemble::GradientBoostingRegressor.new(n_jobs: -1, random_seed: 1),
    rdg: Rumale::LinearModel::LinearRegression.new
  },
  meta_estimator: Rumale::LinearModel::Ridge.new(reg_param: 10),
  random_seed: 1
)

これを実行すると、以下のようになる。ランダム森単体のときよりも、スコアが向上していることがわかる。

$ ruby regression.rb
R2-Score: 0.5751

さらにもう一歩スコアを伸ばしたい場合に、スタッキングを試してみるのは、有効であると考える。

おわりに

スタッキングはKaggleでよく使われ、アンサンブル手法として有名になった。研究自体は90年代初頭からあり、回帰分析では、二段目のメタ学習器の係数に、非負の制限をつけたほうが良いという知見もあったりする。次のバージョンで、非負最小二乗法による回帰を実装しても良いかなとか思ったり。

github.com