モデルを構築して予測して、はい終わり。ではなく、きちんとどの要素がどれくらい結果に寄与しているのかを説明できた方がよいかと思います。
そんな時に、モデルに利用した特徴量の重要度を算出する方法を知っておくと便利です。
というわけで、重要度算出方法として、ツリー系アルゴリズムのfeature_importances_とeli5について書いていこうと思います。
今回利用するデータセット
アヤメの分類のデータセットを使います。
1 2 3 4 5 6 7 |
import pandas as pd from sklearn.datasets import load_iris iris = load_iris() df = pd.DataFrame(iris.data,columns=iris.feature_names) df["y"] = iris.target df.head() |
▼データセットについて
“setosa”, “versicolor”, “virginica” という 3 種類の品種のアヤメのがく片 (Sepal)、花弁 (Petal) の幅および長さを計測したデータです。
データセットの詳細
レコード数 150 カラム数 4 主な用途 分類 (Classification) データセットの詳細 UCI Machine Learning Repository: Iris Data Set 各カラムの構成
sepal length (cm) がく片の長さ sepal width (cm) がく片の幅 petal length (cm) 花弁の長さ petal width (cm) 花弁の幅
3種の品種を機械学習で分類した際に、どの特徴量(花弁の長さ、等)がその分類に寄与しているのかどうかを数字で見えるようにしよう、というのが今回の趣旨です。
ツリー系アルゴリズムのfeature_importances_属性を使う
決定木ベースのアルゴリズムには、scikit-learnでfeature_importances_属性が備わっており、これにより特徴量ごとの重要度がわかります。
試しに、decisiontree, randomforest, xgboostの3つでやってみます。
、、の前にデータを訓練用と検証用に分割します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#データを分割 from sklearn.model_selection import train_test_split X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=1,shuffle=True) print(X.shape) print(X_train.shape) print(X_test.shape) ''' (150, 4) (112, 4) (38, 4) ''' |
モデルを構築して、精度を見ておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
from sklearn.metrics import confusion_matrix,accuracy_score #決定木 from sklearn.tree import DecisionTreeClassifier dt = DecisionTreeClassifier(random_state=2019) dt.fit(X_train,y_train) y_pred = dt.predict(X_test) print("accuracy_score : {}".format(accuracy_score(y_test,y_pred))) ''' accuracy_score : 0.9736842105263158 ''' #ランダムフォレスト from sklearn.ensemble import RandomForestClassifier rf = RandomForestClassifier(random_state=2019) rf.fit(X_train,y_train) y_pred = rf.predict(X_test) print("accuracy_score : {}".format(accuracy_score(y_test,y_pred))) ''' accuracy_score : 0.9736842105263158 ''' #XGBoost import xgboost as xgb from xgboost import XGBClassifier xgb = xgb.XGBClassifier(booster="gbtree",silent=0,seed=2019) xgb.fit(X_train,y_train) y_pred = xgb.predict(X_test) print("accuracy_score : {}".format(accuracy_score(y_test,y_pred))) ''' accuracy_score : 0.9736842105263158 ''' |
3つのモデルで同じ予測精度が出ました。
ではそれぞれでどのように特徴量を評価しているかをみてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#XGBoostの特徴量重要度を見る print(xgb.feature_importances_) ''' array([0.02146471, 0.02318341, 0.5348213 , 0.4205306 ], dtype=float32) ''' #3つのモデルの特徴量重要度を並べてみる models = ["DT","RF","XGB"] importances = pd.DataFrame({"features":iris.feature_names, models[0]:dt.feature_importances_, models[1]:rf.feature_importances_, models[2]:xgb.feature_importances_}) #データフレームをDTの降順に並び替えて表示 importances.sort_values("DT",ascending=False) |
この結果を見る限りですと、sepal length , sepal widthは分類にほとんど寄与していないようです。
一方で、petal length とpetal widthに関しては、モデルごとに扱い方が変わっていて、決定木ではpetal widthを非常に重要視していることがわかります。
Permutaion Importancesを使う
ツリー系アルゴリズム以外の場合にも重要度評価したい、という場合にPermutation Importanceというものが使えるようです。(ツリー系アルゴリズムでも使えます。)
これは、
学習済みのモデルに対し、ある一つの系列が有用でない状態の評価データに対しての予測や分類を各系列に対して行わせ、その際の精度の減少の様子から特徴量の重要度を評価する手法
(https://bunseki-train.com/permutation_importance_and_eli5_1/)
だそうです。
詳細は以下のブログで丁寧に解説されています。
https://bunseki-train.com/permutation_importance_and_eli5_1/
https://bunseki-train.com/permutation_importance_and_eli5_2/
今回は先ほどみたfeature_importances_での重要度評価と、permutation importancesによる重要度評価を見比べてみたいと思います。
はじめに、
1 |
pip install eli5 |
でeli5をインストールしておきましょう。
決定木で比べてみる
※X_train,y_trainを用いて決定木モデルを作った前提で進みます。
1 2 3 4 5 6 7 8 9 10 11 12 |
import eli5 from eli5.sklearn import PermutationImportance perm = PermutationImportance(dt,random_state=2019) perm.fit(X_test,y_test) eli5.show_weights(perm,feature_names=iris.feature_names) #重要度を表示 eli5.show_weights(perm,feature_names=iris.feature_names) #重要度をデータフレームで表示 eli5.explain_weights_df(perm,feature_names=iris.feature_names) |

と、このようになりました。
feature_importances_での重要度評価は、

こうですので、きちんとpetal widthの評価が最も高くなっていますが、細かく見るとsepal系の特徴量が0になっていたり違いがありますね。
どの要素がもっとも寄与しているか、なんて見方をするのにはよさそうです。
XGBoost
同様にXGBoostでも見てみます。
1 2 3 |
perm = PermutationImportance(xgb,random_state=2019) perm.fit(X_test,y_test) eli5.explain_weights_df(perm,feature_names=iris.feature_names) |
XGBでも特徴量の重要度の順位はfeature_importances_でみたときと同じになっています。
ただ、eli5ではpetal widthとpetal lengthの重要度の乖離が大きく見えます。
やはり順位に着目して結果を見るのがよさそうです。
※show_predictionで行ごとの予測も見られる
モデル全体での重要度はexplain_weightsで先ほどのように見ることができましたが、eli5では1行ごとの予測での特徴量の重要度も見ることができます。
現在テストデータの1番目のアヤメは、以下のような値を持っています。
1 2 3 4 5 |
X_test[0] ''' array([5.8, 4. , 1.2, 0.2]) ''' |
これが0,1,2(“setosa”, “versicolor”, “virginica” )のどの分類に属する確率が高いか、というのと、その予測にどの特徴量が寄与しているかをshow_predictionで表示してみましょう。
1 |
show_prediction(xgb,doc=X_test[0],feature_names=iris.feature_names,show_feature_values=True) |
結果を見ると、テストデータ1番目のアヤメは、0(“setosa”)に分類される確率が98%で、それはpetal lengthの値がほぼ寄与したようです。
ちなみに6番目を見ると、、
1 |
eli5.show_prediction(xgb,doc=X_test[5],feature_names=iris.feature_names,show_feature_values=True) |
13番目のアヤメはこのように。
1 |
eli5.show_prediction(xgb,doc=X_test[12],feature_names=iris.feature_names,show_feature_values=True) |
全体だけでなく、行ごとでの重要度が見られるのは楽しいですね。
というわけで、モデルの特徴量重要度の見方に関してのまとめでした。
どこぞの自分と同じ機械学習初学者さんの参考になれば幸いです。
最後まで読んでいただきありがとうございました。