RFE,RFECVの削減過程の精度を追跡したはなし
RFE,RFECVの削減過程の精度を追跡したはなし
背景
発端
少し前に
「RFE,RFECVで変数を削減して欲しい!削減過程のモデルの精度もクレメンス!」
とお願いされた。
できなさそう
今となっては記憶が定かではないが、RFE単体ではそもそも精度を追跡することはできず、RFECV単体では精度追跡はできるけど、どの変数が削減された時に精度なのかが非常にわかりにくかった気がする
対応策
RFEもRFECVも、それぞれ実行後に得られる .ranking_ を使えば、どの変数がどの順番で削減されたのかというのはわかるらしい(でも精度はわからないので注意)
なので対応策として、RFE,RFECV過程での精度追跡は諦める。 .ranking_ を使うことで、どの変数がどの順番で削減されるかを取得し、その順番に沿って別途モデルを再構築する
という周りくどいことをした。
プログラム
RFECVもRFEと同じように対策できるので、RFECV版のプログラムは省略します
その1
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_selection import RFE, RFECV
from sklearn.model_selection import StratifiedKFold
import matplotlib.pyplot as plt
from sklearn.model_selection import cross_val_score
# データの読み込み
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target)
# モデルの準備
estimator = RandomForestClassifier(n_estimators=100, random_state=42)
# RFE(特徴量5個に絞る例)
rfe = RFE(estimator=estimator, n_features_to_select=5)
rfe.fit(X, y)
ここまでで一旦区切る
やったことはライブラリをインストールして、データ作成してRFE実行まで。
その2の前に
rfe.ranking_
RFE実行後にこの中身をみると、どの変数がどの順番で削除されたのかがわかる。
一番ランクが低い変数から順に削除されてる。1位の変数が複数あるが、これは削除されなかった変数。
array([ 8, 10, 2, 4, 15, 14, 6, 1, 25, 26, 12, 24, 17, 9, 20, 19, 18,
22, 21, 23, 1, 3, 1, 1, 7, 11, 5, 1, 13, 16])
それからこのままだと変数名じゃなくて、変数のインデックスで入ってるのでちょっとみにくい。
だからRFEその2の項ではまずそれを解消する
その2
# ランキングと特徴量のデータフレームを作成する
ranking_rfe_df = pd.DataFrame({
"Feature": data.feature_names,
"Elimination Rank": rfe.ranking_
}).sort_values(by="Elimination Rank", ascending=False)
ranking_rfe_df = ranking_rfe_df.reset_index(drop=True)
display(ranking_rfe_df)
# 削減された変数
print(len(ranking_rfe_df[ranking_rfe_df["Elimination Rank"]!=1]))
# 削減されなかった変数
print(len(ranking_rfe_df[ranking_rfe_df["Elimination Rank"]==1]))
最初のデータフレーム作成で以下のようなデータフレームを得られる。
これによりどの変数がどの順番で削除されたのか、ようやくわかりやすくなった。
それから順位が飛び飛びなのは記事を見やすくするために省略したから
Feature | Elimination Rank |
---|---|
mean fractal dimension | 26 |
mean symmetry | 25 |
worst concavity | 4 |
worst concave points | 3 |
worst area | 2 |
mean concave points | 1 |
mean concavity | 1 |
mean perimeter | 1 |
その3
あとはこのデータフレームを使ってあげれば、for文を回すだけで精度追跡ができるよ
# 削除された変数を取得(Elimination Rank の降順でソート)
drop_cols = list(
ranking_rfe_df[ranking_rfe_df["Rank"] != 1]
.sort_values(by="Rank", ascending=False)["Feature"]
)
print("削除対象:\n",drop_cols)
# 全使用変数
use_cols = list(data.feature_names)
all_cols_cnt = len(use_cols)
# 精度記録用
res_df = pd.DataFrame(columns=["削除した変数名","削除した変数数","Mean Accuracy"])
# 各特徴量を1つずつ除いてモデル学習&評価
for i in range(-1, len(drop_cols)):
# 特徴量削減
if i != -1 :
drop_col = drop_cols[i] # イテレータが0以上なら、イテレータとdrop_cols内の削除変数の順番が一致する
use_cols.remove(drop_col)
elif i==-1:
drop_col = None # -1なら削減しないのでNoneに設定する
# CV
scores = cross_val_score(estimator, X[use_cols], y, cv=5, scoring='accuracy')
avg_score = scores.mean()
# CV結果と削除変数記録
tmp_df = pd.DataFrame({
"削除した変数名": [drop_col],
"削除した変数数": [all_cols_cnt - len(use_cols)],
"Mean Accuracy": [avg_score]})
res_df = pd.concat([res_df, tmp_df],axis=0)
res_df.reset_index(drop=True)
display(res_df)
結果はこんな感じ
削除した変数数の値を使えば精度の折れ線グラフも作れます。
今回は省略しますが、折れ線グラフ自体は簡単に作れるので、よかったらお試しを。
削除した変数名 | 削除した変数数 | Mean Accuracy |
---|---|---|
None | 0 | 0.956094 |
mean fractal dimension | 1 | 0.964881 |
mean symmetry | 2 | 0.970160 |
texture error | 3 | 0.961357 |
fractal dimension error | 4 | 0.959587 |
concave points error | 5 | 0.959587 |
radius error | 6 | 0.961373 |
mean radius | 7 | 0.956094 |
symmetry error | 8 | 0.959587 |
smoothness error | 9 | 0.956094 |
worst symmetry | 10 | 0.954324 |
mean texture | 11 | 0.954324 |
mean smoothness | 12 | 0.950798 |
mean compactness | 13 | 0.956109 |
compactness error | 14 | 0.956109 |
perimeter error | 15 | 0.954339 |
worst fractal dimension | 16 | 0.959587 |
worst smoothness | 17 | 0.959587 |
worst compactness | 18 | 0.961357 |
area error | 19 | 0.961357 |
concavity error | 20 | 0.961357 |
mean concavity | 21 | 0.961357 |
worst concavity | 22 | 0.956109 |
mean area | 23 | 0.956109 |
worst texture | 24 | 0.945552 |
mean perimeter | 25 | 0.945536 |
Discussion