多数決アンサンブル分類器(votingclassifier)の使い方
機械学習では、精度向上を狙って複数の予測器のアンサンブルを行うことも少なくありません。この記事では、scikit-learnの多数決アンサンブル分類器(sklearn.ensemble.votingclassifier)の使い方について解説します。
Votingclassfierとは
VotingClassifier
は、scikit-learnライブラリで提供されているアンサンブル学習の手法の一つです。アンサンブル学習は、複数の機械学習モデルを組み合わせて、単一のモデルよりも優れた性能を達成しようとする手法です。
VotingClassifier
では、複数の分類器(クラス分類器)の予測を組み合わせることにより、投票に基づいて最終的な予測を行います。
具体的には、異なる種類の分類器(例: ロジスティック回帰、決定木、ランダムフォレストなど)を用意し、各分類機の結果投票によってクラスを選択します。
VotingClassifier
は、ハード(各分類器の予測の多数決による投票)またはソフト(各分類器のクラス確率の平均を計算し、最も確率の高いクラスを選択)のいずれかを使用することができます。
ここでは、VotingClassifierの使い方を、実際に動かしながら解説します。
Votingclassfierの使い方①
データセット(iris)
利用するデータセットは、おなじみのscikit-learnのirisデータセットです。このデータセットを使って、花びら(petal)/がく片(sepal)の長さと幅(cm)という4つの特徴量から、あやめの種類(setosa, versicolor, virginicaの3種類)を予測します。
まずは、load_iris()
でデータを読み込んで、訓練データ(train
)とテストデータ(test
)に分けます。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.25)
KNNで予測
1つ目の予測器はKNN(k近傍法)にしました。KNNはscikit-learnで用意されているものを利用します。
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
y_pred1 = knn.predict(X_test)
print(y_pred1)
# [0 2 0 1 0 1 0 2 1 2 2 2 1 1 0 2 2 1 1 0 2 1 2 1 0 0 1 2 1 2 0 1 0 2 1 2 0 1]
SVCで予測
2つ目の予測器はSVM(サポートベクターマシン)です。こちらもscikit-learnで用意されているものを利用します。probability=True
のオプションは、VotingClassifierでsoft
を使う場合に必要になるため設定しています。
from sklearn.svm import SVC
svc = SVC(probability=True)
svc.fit(X_train, y_train)
y_pred2 = svc.predict(X_test)
print(y_pred2)
# [0 2 0 1 0 1 0 2 1 2 2 2 1 1 0 2 2 1 1 0 2 1 2 1 0 0 1 2 1 2 0 1 0 2 1 2 0 1]
LightGBMで予測
3つ目はkaggleなどでもよく利用されているLightGBMです。ここでは、scikit-learnの形式のインタフェースを利用しています。
import lightgbm as lgb
lgbm = lgb.LGBMClassifier(verbose=-1)
lgbm.fit(X_train, y_train)
y_pred3 = lgbm.predict(X_test)
print(y_pred3)
# [0 2 0 1 0 1 0 2 1 2 2 2 1 1 0 2 2 1 1 0 2 1 2 1 0 0 1 2 1 2 0 1 0 2 1 2 0 1]
予測精度を確認
3つの予測器の予測精度を表示してみます。
# 3つの結果を表示
print(accuracy_score(y_test, y_pred1))
print(accuracy_score(y_test, y_pred2))
print(accuracy_score(y_test, y_pred3))
題材の問題か、予測精度は全ての予測機で同じでした。
予測結果がばらつかないとアンサンブルが面白くないかも
0.9473684210526315
0.9473684210526315
0.9473684210526315
VotingClassifierで予測
3つの予測器を用意しましたので、VotingClassifierで3つの予測器を使って予測してみます。
使い方
VotingClassifier
では、estimators
パラメータで予測機の(名前と予測器)のリストを渡します。VotingClassifier
の主な引数は以下になります。
VotingClassifier
の主な引数引数名 | 説明 |
---|---|
estimators | 分類器を設定するパラメータ。[('name', model), …] のように分類器の名前と分類器のオブジェクトのペアをリスト形式で渡します |
voting | 投票方法を設定するパラメータ。hard の場合は多数決。soft の場合は、書く予測器の予測値(確率)の平均をとって、最も確率が高いクラスを返します |
weights | 各予測機の重みのリスト |
n_jobs | 並列実行の数。-1を設定した場合はすべてのプロセッサを利用 |
verbose | verboseのon/off |
後の使い方は、他の分類器と同じでfit()
→predict()
の順で呼び出します。
VotingClassifier(HARD)で予測
voting='hard'
で予測した結果です。3つの予測器の結果が同じなので、投票結果も同じです。
from sklearn.ensemble import VotingClassifier
voting_classifier = VotingClassifier(estimators=[('knn', knn), ('lgb', lgbm), ('svc', svc)], voting='hard')
voting_classifier.fit(X_train, y_train)
y_pred = voting_classifier.predict(X_test)
print(y_pred)
print(accuracy_score(y_test, y_pred))
[0 2 0 1 0 1 0 2 1 2 2 2 1 1 0 2 2 1 1 0 2 1 2 1 0 0 1 2 1 2 0 1 0 2 1 2 0 1]
0.9473684210526315
VotingClassifier(SOFT)で予測
voting='hard'
で予測した結果です。こちらも同じ結果になりました。
from sklearn.ensemble import VotingClassifier
voting_classifier = VotingClassifier(estimators=[('knn', knn), ('lgb', lgbm), ('svc', svc)], voting='soft')
voting_classifier.fit(X_train, y_train)
y_pred = voting_classifier.predict(X_test)
print(y_pred)
print(accuracy_score(y_test, y_pred))
[0 2 0 1 0 1 0 2 1 2 2 2 1 1 0 2 2 1 1 0 2 1 2 1 0 0 1 2 1 2 0 1 0 2 1 2 0 1] 0.9473684210526315
Votingclassfierの使い方②
irisデータの結果が面白くなかったので、VotingClassifier
を使って別のデータセットの予測を行ってみることにしました。
make_classificationを使ってデータセットを作成
scikit-learnのmake_classification
関数を使うと、「ランダムな n クラス分類問題」を生成することができます。ここでは、これを使ってデータセットを作ってVotingClassification
の動作を確認してみます。
使い方
使い方は簡単です。以下のように呼び出すだけで、データXとラベルyを作成してくれます。データポイントはガウス分布に従い生成されるため、実際に分類問題のサンプルとして利用することができます。
今回は、この擬似データを使って分類を試します。
X, y = make_classification(n_samples=1000, n_features=20, random_state=1234)
この関数の引数は以下になります(一部省略しています)。
make_classification
の代表的な引数引数 | 内容 |
---|---|
n_samples | サンプル数 |
n_features | 特徴量の数 |
n_informative | 目的変数のラベルと相関が強い特徴量の数 |
random_state | 乱数のシード |
VotingClassifier(2クラス分類)サンプル
make_classification
で2クラスのデータセットを作成して予測を行ってみます。
ここでは、XGBoost, LightGBM, KNNの3つを組み合わせています。
LightGBMとXGBoostはどちらもブースティングなので、アンサンブルするには向かないかもしれませんが、私が頻繁に利用しているのでサンプルに組み入れました。
from sklearn.ensemble import VotingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
import lightgbm as lgb
from xgboost import XGBClassifier
# lgbm = lgb.LGBMClassifier(verbose=-1)
# サンプルデータの生成
# n_samples サンプル数
# n_features 特徴量の数
# n_informative 目的変数のラベルと相関が強い特徴量の数
X, y = make_classification(n_samples=1000, n_features=20, random_state=42, n_informative=12)
# モデルの定義
model1 = XGBClassifier()
model2 = lgb.LGBMClassifier(verbose=-1)
model3 = KNeighborsClassifier()
# 投票分類器の構築
voting_classifier = VotingClassifier(estimators=[('xgb', model1), ('lgb', model2), ('knn', model3)], voting='hard')
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# モデルの訓練
model1.fit(X_train, y_train)
model2.fit(X_train, y_train)
model3.fit(X_train, y_train)
voting_classifier.fit(X_train, y_train)
# 予測
y_pred1 = model1.predict(X_test)
y_pred2 = model2.predict(X_test)
y_pred3 = model3.predict(X_test)
y_pred = voting_classifier.predict(X_test)
# 精度の評価
accuracy1 = accuracy_score(y_test, y_pred1)
accuracy2 = accuracy_score(y_test, y_pred2)
accuracy3 = accuracy_score(y_test, y_pred3)
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy1: {accuracy1}')
print(f'Accuracy2: {accuracy2}')
print(f'Accuracy3: {accuracy3}')
print(f'Voting Accuracy: {accuracy}')
結果は、それぞれの予測器単体より、投票した結果が良くなっています(これを期待していました)。Votingの効果が見える形になりました。
Accuracy1: 0.935
Accuracy2: 0.935
Accuracy3: 0.93
Voting Accuracy: 0.94
VotingClassifier(5クラス分類)サンプル
同様に5クラスのデータセットを作成して予測してみました。プログラム的にはほぼ同じです。
from sklearn.ensemble import VotingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
import lightgbm as lgb
from xgboost import XGBClassifier
# サンプルデータの生成
X, y = make_classification(n_samples=1000, n_features=20, random_state=42, n_classes=5, n_informative=12)
# モデルの定義
model1 = XGBClassifier()
model2 = lgb.LGBMClassifier(verbose=-1)
model3 = KNeighborsClassifier()
# 投票分類器の構築
voting_classifier = VotingClassifier(estimators=[('xgb', model1), ('lgb', model2), ('knn', model3)], voting='hard')
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# モデルの訓練
model1.fit(X_train, y_train)
model2.fit(X_train, y_train)
model3.fit(X_train, y_train)
voting_classifier.fit(X_train, y_train)
# 予測
y_pred1 = model1.predict(X_test)
y_pred2 = model2.predict(X_test)
y_pred3 = model3.predict(X_test)
y_pred = voting_classifier.predict(X_test)
# 精度の評価
accuracy1 = accuracy_score(y_test, y_pred1)
accuracy2 = accuracy_score(y_test, y_pred2)
accuracy3 = accuracy_score(y_test, y_pred3)
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy1: {accuracy1}')
print(f'Accuracy2: {accuracy2}')
print(f'Accuracy3: {accuracy3}')
print(f'Voting Accuracy: {accuracy}')
こちらも、個別の予測器よりも良い結果を得ることができました。
Accuracy1: 0.78
Accuracy2: 0.74
Accuracy3: 0.78
Voting Accuracy: 0.795
データセットによっては、単体の方がよい結果を出すこともありました。常にVotingの方が良い結果になるわけではないので、評価実験が必要です。
まとめ
scikit-learnのVotingClassifierについて解説しました。簡単にアンサンブルできるので、複数の予測器の結果を組み合わせるのに使ってみてはどうでしょうか。
特徴量エンジニアリングなどの手法については以下の記事を参考にしてください