post Image
アンサンブル学習(Stacked generalization)のサンプルプログラムと実行例

はじめに

本記事はPython2.7, numpy 1.11, scipy 0.17, scikit-learn 0.18, matplotlib 1.5, seaborn 0.7, pandas 0.17を使用しています.
jupyter notebook上で動作確認済みです.

Kaggleで単純な分類問題解くとき,MLWaveのAnsembling-guideをよく使っています.
日本語でまとめたサイトがあまりなかったので,サンプルプログラムも添えて書いて見ました.

目次

  1. データの生成
  2. アンサンブル学習で使用する分類器の準備
  3. アンサンブル学習の実装
  4. 評価
  5. 参考

1. データの生成

自前のデータがあればここは無視してください.

こちらのmake_classificationを用いて3次元2クラスのデータを2000サンプル作成します.
ラベルデータの比率を1:1に揃えるため,make_classification(flip_y=0)としています.

その後,生成したデータをtrainとtestへ半々に分割しています.

make_classification.py
from sklearn.datasets import make_classification
import pandas as pd
import numpy as np

n_features = 3
n_samples = 2000
data = np.c_[make_classification(n_samples=n_samples, n_features=n_features, n_redundant=1, n_informative=2,n_clusters_per_class=2, n_classes=2, flip_y=0)]

train = test = np.empty((0,n_features+1), float)
for d in [data[data[:, n_features]==0], data[data[:, n_features]==1]]:
    np.random.shuffle(d)
    train = np.append(train, d[:(n_samples/4)], axis=0)
    test = np.append(test, d[(n_samples/4):], axis=0)
map(lambda x: np.random.shuffle(x), [train, test])

train, testの中身はこんな感じ.

array([[-0.96155185, -0.49879683,  0.65487916,  1.        ],
       [-0.95225926, -1.00853786, -0.97598077,  0.        ],
       [-0.11578056,  2.51579129, -1.23724233,  0.        ],
       ..., 
       [-0.93715662,  0.41894292, -1.56002152,  0.        ],
       [-0.69759832, -0.20810317, -0.01283087,  0.        ],
       [ 0.31519506, -1.75498218,  0.89115054,  1.        ]])

これで数値データ3つとラベルデータが準備できました.

2. アンサンブル学習で使用する分類器の準備

機械学習アルゴリズムを準備します.
今回使用するのは,RandomForest, KNN, ExtraTree, GradientBoosting, NaiveBays, XGBoostの6種類です.XGBoost以外はscikit-learnを使用しており,単純にインポートするだけで済みます.XGBoostはpip installかgitでビルド可能です.

アンサンブル学習で使用する分類器のリストを作成します.

  • n_jobs=-1としているので,並列計算となります.必要に応じて修正してください
  • 今回は使用していませんが,XGBoost 0.6以降ではeval_matrixパラメータがなくなっています
set_clfs.py
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.naive_bayes import GaussianNB
from xgboost import XGBClassifier
from sklearn.neighbors import KNeighborsClassifier

clfs = [RandomForestClassifier(n_estimators=100, n_jobs=-1, criterion='gini'),
        ExtraTreesClassifier(n_estimators=100, n_jobs=-1, criterion='gini'),
        GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=50),
        KNeighborsClassifier(n_neighbors=10, n_jobs=-1),
        GaussianNB(),
        XGBClassifier(learning_rate =0.1, n_estimators=1000, max_depth=5, min_child_weight=1,
              gamma=0, subsample=0.8, colsample_bytree=0.5, objective= 'binary:logistic',
              scale_pos_weight=1, seed=0
             )
       ]

試しにKNNで二値分類をしてみます.

knn.py
from sklearn.metrics import accuracy_score

nbrs = KNeighborsClassifier().fit(train[:, :-1], train[:, -1])
print "Acc: ", accuracy_score(test[:, -1], nbrs.predict(test[:, :-1]))
Acc:  0.90

精度は90%となりました.
アンサンブル学習の結果,この精度がどう変化するか比較していきます.

3. アンサンブル学習の実装

Kaggleなどのコンペで単純な(画像や連続値でない)分類問題を取り扱う場合は,単一の学習器を使うことはほとんどありません.複数の機械学習を組み合わせるアンサンブル学習が用いられます.
知っている限りアンサンブル学習を最も詳しく解説しているサイトは,MLWaveのこちらの記事になります.

  • Voting
  • Averaging
  • Rank averaging
  • Stacked generalization & blending

主要なアンサンブル学習はこれらの4つです.リンク先の記事では,Kaggleでの実際の使用例が詳しく説明されています.非常に親切なことに,githubでこれらを活用するフレームワークまで公開しています.
今回はStacked generalization & blendingについて紹介します.
(githubではblend_proba.pyというプログラムです)

3.1 blend_proba()の使用例

本関数は,二値分類をアンサンブル学習で解くためのフレームワークになります.中身は非常にシンプルなので,時間がある方はコードをチェックしてみてください.
ここでは次のような方法で学習していきます.

Picture1.png

step 1

  • まずはじめに,生成したデータをRandomForest, KNN, ExtraTree, NaiveBays, GradientBoosting, XGBoostでそれぞれ学習させていきます.
  • Trainingデータで学習した分類器を使って,Testingデータの評価まで同時に行います.

blend_probaをインポートした後,次のプログラムを実行します.

step1.py
import blend_proba as bp
[bp.blend_proba(clf, X_train=train[:, :-1], y=train[:, -1], X_test=test[:, :-1], save_preds="1", nfolds=3) for clf in clfs]

実行後,実行したディレクトリにnpyファイルが生成されています.

1GB_0.303855837305_16482164617e7c9d188bc75bafc06a08_test.npy
1GB_0.303855837305_16482164617e7c9d188bc75bafc06a08_train.npy
1Ne_0.455167671362_cddd24af66706c9fa26f6601910c92c5_test.npy
1Ne_0.455167671362_cddd24af66706c9fa26f6601910c92c5_train.npy
1an_0.249015612417_825e1ad5956801c2225da656822caebb_test.npy
1an_0.249015612417_825e1ad5956801c2225da656822caebb_train.npy
1au_0.22545173232_4b57dac04bbc037494cb592143a1c09c_test.npy
1au_0.22545173232_4b57dac04bbc037494cb592143a1c09c_train.npy
1ra_0.207753858339_a0cb35c894f0ad378f6bb824e1019748_test.npy
1ra_0.207753858339_a0cb35c894f0ad378f6bb824e1019748_train.npy
1xt_0.270981174382_e130a295809821efc1db2f64c228169c_test.npy
1xt_0.270981174382_e130a295809821efc1db2f64c228169c_train.npy

save_preds=”?”と設定することで,”?+分類器名の2~3文字目+ハッシュ値+test(or train).npyという名前の予測結果がprobabilityで出力されます.
この場合,分類器の数が6つなので12個のnpyファイルが生成されます.

step 2

まず,step 1で生成したファイルを読み込む関数を作成します.

  • ここでは,step 1で生成したnpyファイルは,’./first/train/’, ‘./first/test/’に入っているとします.
  • step 1で得た二値分類の予測結果(0から1の連続値)を入力とする
read_first_stage.py
import sys,os

def read_npy(tr_p, te_p):
    train_file_names = map(lambda x: tr_p + x, os.listdir(tr_p))
    test_file_names = map(lambda x: te_p + x, os.listdir(te_p))

    list_train, list_test = [], []
    for path_train, path_test in zip(train_file_names, test_file_names):
        frame_train, frame_test = np.load(path_train), np.load(path_test)
        list_train.append(frame_train)
        list_test.append(frame_test)
    l_train, l_test = list_train[0], list_test[0]
    for train_, test_ in zip(list_train[1:], list_test[1:]):
        l_train = np.concatenate([l_train, train_], axis=1)
        l_test = np.concatenate([l_test, test_], axis=1)
    return l_train, l_test

first_train, first_test = read_npy('./first/train/', './first/test/')
print first_train

trainデータのnpyファイルを読み込んで連結した結果がこちらです.
二値分類の予測結果が学習器ごとに入っており,trainとtestには12個の変数が含まれています.

array([[  1.07884407e-04,   9.99892116e-01,   0.00000000e+00, ...,
          9.93333333e-01,   2.50875433e-04,   9.99749125e-01],
       [  9.96784627e-01,   3.21540073e-03,   9.76666667e-01, ...,
          2.00000000e-02,   9.53099981e-01,   4.69000190e-02],
       [  5.11407852e-05,   9.99948859e-01,   5.33333333e-02, ...,
          9.06666667e-01,   1.66652470e-06,   9.99998333e-01],
       ..., 
       [  4.93575096e-01,   5.06424904e-01,   6.30000000e-01, ...,
          4.03333333e-01,   9.49199952e-01,   5.08000478e-02],
       [  3.96782160e-03,   9.96032178e-01,   2.66666667e-02, ...,
          9.46666667e-01,   2.46422552e-06,   9.99997536e-01],
       [  9.99466836e-01,   5.33185899e-04,   9.03333333e-01, ...,
          8.00000000e-02,   9.54109081e-01,   4.58909185e-02]])

このstep 1の評価結果を使用して,step 2の学習を行います.

step2.py
[bp.blend_proba(clf, X_train=first_train, y=train[:, -1], X_test=first_test, save_preds="2", nfolds=3) for clf in clfs]

実行後,12個のnpyファイルが生成されます.

2GB_0.37311622448_16482164617e7c9d188bc75bafc06a08_test.npy
2GB_0.37311622448_16482164617e7c9d188bc75bafc06a08_train.npy
2Ne_0.784523345103_cddd24af66706c9fa26f6601910c92c5_test.npy
2Ne_0.784523345103_cddd24af66706c9fa26f6601910c92c5_train.npy
2an_0.421335902473_825e1ad5956801c2225da656822caebb_test.npy
2an_0.421335902473_825e1ad5956801c2225da656822caebb_train.npy
2au_1.9348828025_4b57dac04bbc037494cb592143a1c09c_test.npy
2au_1.9348828025_4b57dac04bbc037494cb592143a1c09c_train.npy
2ra_0.292331269114_a0cb35c894f0ad378f6bb824e1019748_test.npy
2ra_0.292331269114_a0cb35c894f0ad378f6bb824e1019748_train.npy
2xt_0.451990280749_e130a295809821efc1db2f64c228169c_test.npy
2xt_0.451990280749_e130a295809821efc1db2f64c228169c_train.npy

step 3

step 2で生成したデータをreadし,XGBoostで学習します.

  • ここでは,step 2で生成したnpyファイルは,’./second/train/’, ‘./second/test/’に入っているとします.
  • save_predsの代わりに,blend_proba(save_test_only=”3″)とすることで,確率ではなく0, 1で出力したファイルを生成します.
step3.py
second_train, second_test = read_data('./second/train/', './second/test/')

clf = XGBClassifier(learning_rate =0.1, n_estimators=1000, max_depth=5, min_child_weight=1,
                    gamma=0, subsample=0.8, colsample_bytree=0.5, objective= 'binary:logistic',
                    scale_pos_weight=1, seed=0
                   )

bp.blend_proba(clf, X_train=second_train, y=second_train[:, -1], X_test=second_test, save_test_only="3", nfolds=3)

3+GB+ハッシュ値+test.txtというファイルが生成されました.
3GB
0.338917307945_16482164617e7c9d188bc75bafc06a08_test.txt

check_ans.py
ans = np.loadtxt('./3GB_0.338917307945_16482164617e7c9d188bc75bafc06a08_test.txt')
print "Acc: ", accuracy_score(test[:, -1], ans)

精度は次の通り.

Acc:  0.90

特に精度が上がったわけではないようです.

4. 評価

何度か試した結果,KNNと比較して精度が変わらない(もしくは低下)結果となりました.
そもそも生成したデータが小規模だったのと,人工的に生成したデータ自体に問題があった可能性があります.
MLWaveで紹介されているように,Kaggleのデータで変数が大量にある場合では,精度のが数%向上することがよくあります.

Kaggle-Ensemble-Guide/correlations.pyについて

サンプルコードの中に,correlations.pyというファイルがあります.
中を見てみると,個々の分類結果から予測結果の相関係数を算出しています.
MLWaveの記事にもありますが,相関の少ない分類器を組み合わせるほど,予測精度の向上が見込めます.
(当たり前の話かもしれませんが)
このように相関係数をチェックしながら,

  • アルゴリズムの組み合わせ
  • オリジナルデータの下処理
  • 分類器のscore関数の調整

をいろいろ試して精度を上げていきます.

多クラス分類について

MLWaveでは,アンサンブル学習を用いた多クラス分類も紹介しています.
記事の中では,各クラスごとにそれぞれアンサンブル学習を実装し,それぞれの予測結果をまとめることで多クラス分類を実装しています.
(One-vs-the-rest)

5. 参考

Kaggle Ensemble Guide


『 機械学習 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。