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