【Pythonで機械学習】過学習対策にRFEを活用した次元削除方法

 

Kaggleのコンペでデータ分析をやっていると、カラム数が100(100次元)を超えるもの、pandas.get_dummies関数を使って、カテゴリ変数の数量化をやるとカラム数が一気に増えてしまうものです。

 

カラム数が増えた状態で機械学習のアルゴリズムに通すと、過学習の原因になることがあります。さらに、学習の時間が増えます。

 

過学習の対策の一つとしてscikit-learnのライブラリーであるRFE(Recursive feature elimination)を使った次元削除の方法を紹介したいと思います!

 

RFE使った効果は?

 

sklearnのbreast-cancerデータセットを使って、カラムを30次元から10次元に削除(次元圧縮)してみました。

次元圧縮後、ロジステック回帰を使って学習しAUCスコアを出して比較しました。

その結果、以下の通りになりました。

 

■30次元でロジステック回帰を実行してみる

AUCスコア=0.979779411764706

 

■10次元でロジステック回帰を実行してみる

AUCスコア=0.9761029411764706

 

次元圧縮前後のAUCスコアの誤差は、0.01程です。

10次元に削除しても精度の高いモデルが出来たと言えます。

 

削除対象のカラムを見てみると、標準偏差の値が小さいカラムが、削除対象になっている印象でした。

 

 

RFEとは何?

 

RFEについて、scikit-learnの公式サイトには以下のように説明があります。

 

1.13.3. Recursive feature elimination

 

Given an external estimator that assigns weights to features (e.g., the coefficients of a linear model), recursive feature elimination (RFE) is to select features by recursively considering smaller and smaller sets of features. First, the estimator is trained on the initial set of features and the importance of each feature is obtained either through a coef_ attribute or through a feature_importances_ attribute. Then, the least important features are pruned from current set of features.That procedure is recursively repeated on the pruned set until the desired number of features to select is eventually reached.

出典:

1.13.3. Recursive feature elimination

 

 

RFEを簡単に説明すると、ランダムフォレストなど実際のモデルにデータを渡して、そこから特徴があるカラムを抽出します。10カラムと指定したら、重要度についてランキング付けをして、上位10位までのカラムを取得します。

 

実際に使ってみると、標準偏差の値が小さいほど、カラムの削除対象になるようです。

 

 

実際に使ってみる

では、実際にRFEを使ってコードを書いてみます。

#ロジステック回帰、および、AUC評価をする関数
def logistic_acu_score(data_x, data_y):
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import StandardScaler
    from sklearn.linear_model import LogisticRegression

    # holdoutでデータ取り出し
    X_train,X_test,Y_train,Y_test=train_test_split(data_x,
                                               data_y,
                                               test_size=0.2,
                                               random_state=4)


    #ロジステック回帰作成
    lr = LogisticRegression() # ロジスティック回帰モデルのインスタンスを作成
    lr.fit(X_train, Y_train) # ロジスティック回帰モデルの重みを学習

    Y_score = lr.predict_proba(X_test)# 検証データがクラス1に属する確率(つまり良性の可能性)
    Y_score = Y_score[:,1]

    from sklearn.metrics import roc_auc_score
    print('aucスコア = ', roc_auc_score(y_true=Y_test, y_score=Y_score))


#ここから処理の開始
#python3.6で実装
#cancerのデータ読み込む(圧縮前のデータ)
import pandas as pd
from sklearn.datasets import load_breast_cancer

#load_breast_cancerのデータを取得
#2値の比較
dataset = load_breast_cancer()
X = pd.DataFrame(dataset.data, columns=dataset.feature_names)
y = pd.Series(dataset.target, name='y')

#どんなデータかを見る
print('----------------------------------------')
print('X shape: (%i,%i)' %X.shape)
print('----------------------------------------')
print(y.value_counts())
print('y=0 means Marignant(悪性), y=1 means Benign(良性):')
print('----------------------------------------')
X.join(y).head()

#消す前のカラムの状態
display(X.columns)


#本当に標準偏差の値が低い順に次元を削除しているのか確認するため
#標準偏差が高い順に並べ替える
data = X.describe()
data = data.T
data.sort_values(by=["std"], ascending=False)

#ロジステック回帰を実行
#AUCスコア=0.979779411764706
logistic_acu_score(X,y)



from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier


#RFEを使って次元を削除する
#今回は10次元まで落とす
selector = RFE(RandomForestClassifier(n_estimators=100,random_state=1),
               n_features_to_select=10,
               step=.05)

selector.fit(X,y)

#次元削除後、どのカラムを消したか確認する
print(selector.support_)

#次元削除後のカラム数を確認する
print(selector.n_features_)

#次元削除後のランキング取得「1」は残したカラム
print(selector.ranking_)

#削除したカラムを出力
#ここでdescribeしている理由は、消えたカラムの特徴を調べるため
#delete_columns = []
#for i  in range(len(X.columns)):
#    if(selector.support_[i]) == False:
#        column = X.columns[i]
#        print (column)
#        print(X.describe()[column])


# 圧縮後のデータを設定してロジステック回帰で学習
X_train = selector.transform(X)


data_x = pd.DataFrame(X_train,columns=X.columns[selector.support_]) #次元削除した説明変数 10個
data_y = pd.Series(dataset.target, name='y') #目的変数

print('X shape after RFE:', data_x.shape)
print('---------------------------------------')
print(data_x.dtypes)


#圧縮後(次元削除後)のdescribeを確認する
#data = data_x.describe()
#data = data.T
#data.sort_values(by=["std"], ascending=False)



#10次元でロジステック回帰でAUCを求めてみる
#結果は、aucスコア は「0.9761029411764706」になった。
logistic_acu_score(data_x, data_y)

 

まとめ

いかがですか?

カラム数が増えてくると、過学習の原因になりがちです。

そんなときは、RFEなど使って、次元圧縮を検討してみてはいかがでしょうか?

 

最新情報をチェックしよう!
>プログラミングスクール検索・比較表サイト

プログラミングスクール検索・比較表サイト

ワンクリック、さらに詳細に条件を指定してプログラミングスクールの検索ができます。さらに比較表により特徴を細かく比較できる!

CTR IMG