機械学習
記事内に商品プロモーションを含む場合があります

多数決アンサンブル分類器(votingclassifier)の使い方

tadanori

機械学習では、精度向上を狙って複数の予測器のアンサンブルを行うことも少なくありません。この記事では、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を設定した場合はすべてのプロセッサを利用
verboseverboseの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について解説しました。簡単にアンサンブルできるので、複数の予測器の結果を組み合わせるのに使ってみてはどうでしょうか。

特徴量エンジニアリングなどの手法については以下の記事を参考にしてください

機械学習の前処理・特徴量エンジニアリングの手法を解説【Python】
機械学習の前処理・特徴量エンジニアリングの手法を解説【Python】

おすすめ書籍

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

記事URLをコピーしました