PythonによるWrapperメソッドの特徴選択への応用

前回は、機械学習アルゴリズムの特徴抽出にフィルタリング手法を用いる方法について検討した。

フィルターメソッドは、すべての機械学習モデルに対して汎用的な特徴量のセットを選択したい場合に便利です。

しかし、あるシナリオでは、特定の機械学習アルゴリズムを使ってモデルを学習させたいことがある。

そのような場合、フィルター法で選択された特徴は、その特定のアルゴリズムにとって最適な特徴セットとは限らない。

特徴選択法には、指定されたアルゴリズムに最適な特徴を選択する別のカテゴリーがある。

特徴抽出のためのラッパーメソッド

Wrapper法は、特徴の全ての可能な組み合わせを評価し、特定の機械学習アルゴリズムに最適な結果をもたらす組み合わせを選択するため、貪欲探索アルゴリズムに基づく。

この手法の欠点は、特徴の全ての可能な組み合わせをテストすることは、特に特徴セットが非常に大きい場合、計算量が非常に多くなることである。

先に述べたように、ラッパー法は特定のアルゴリズムに最適な特徴セットを見つけることができる。

しかし、これらの特徴セットが他のすべての機械学習アルゴリズムに最適とは限らないという欠点がある。

特徴抽出のためのラッパーの手法は、3つのカテゴリーに分けられる。

ステップフォワード特徴選択、ステップバック特徴選択、そして網羅的特徴選択である。

今回は、これらの特徴選択手法をPythonでどのように実装するかを見ていきます。

ステップフォワード機能選択

ステップフォワード特徴抽出の最初のフェーズでは,各特徴に対する分類器の性能が評価されます.そして,すべての特徴量の中から,最も性能の良い特徴量が選択されます.

第2段階では,最初の特徴を他の全ての特徴と組み合わせて試す.そして、最も良いアルゴリズムの性能を示す2つの特徴の組み合わせが選択される。

このプロセスは、指定された数の特徴が選択されるまで続けられる。

それでは、Pythonでステップフォワード特徴選択を実装してみましょう。

ここでは、前回と同様にBNP Paribas Cardif Claims Managementのデータセットを使用します。

ステップフォワード特徴選択を実装するためには、カテゴリ的な特徴値を数値的な特徴値に変換する必要があります。

しかし、ここでは簡単のため、データから非カテゴリカルの列をすべて削除します。

また、前回の記事で行ったように相関のある列も削除し、処理する特徴セットを小さくする。

データ前処理

次のスクリプトはデータセットと必要なライブラリをインポートし、データセットから非数値の列を削除し、データセットをトレーニングセットとテストセットに分割するものである。

最後に、相関が0.8より大きいカラムをすべて削除します。

このスクリプトの詳細については、こちらの記事を参照されたい。

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import VarianceThreshold


paribas_data = pd.read_csv(r"E:Datasetsparibas_data.csv", nrows=20000)
paribas_data.shape


num_colums = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numerical_columns = list(paribas_data.select_dtypes(include=num_colums).columns)
paribas_data = paribas_data[numerical_columns]
paribas_data.shape


train_features, test_features, train_labels, test_labels = train_test_split(
    paribas_data.drop(labels=['target', 'ID'], axis=1),
    paribas_data['target'],
    test_size=0.2,
    random_state=41)


correlated_features = set()
correlation_matrix = paribas_data.corr()
for i in range(len(correlation_matrix .columns)):
    for j in range(i):
        if abs(correlation_matrix.iloc[i, j]) > 0.8:
            colname = correlation_matrix.columns[i]
            correlated_features.add(colname)


train_features.drop(labels=correlated_features, axis=1, inplace=True)
test_features.drop(labels=correlated_features, axis=1, inplace=True)


train_features.shape, test_features.shape


Pythonによるステップフォワード特徴抽出の実装

最適な素性を選択するために、mlxtendライブラリの SequentialFeatureSelector 関数を使用します。

ライブラリは、anacondaのコマンドプロンプトで以下のコマンドを実行してダウンロードすることができます。

conda install -c conda-forge mlxtend


最適なパラメータを見つけるために、ランダムフォレスト分類器を使用する予定です。

評価基準はROC-AUCを使用します。

以下のスクリプトは、データセットからランダムフォレスト分類器に最適な性能をもたらす15個の特徴を選択するものです。

from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score


from mlxtend.feature_selection import SequentialFeatureSelector


feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
           k_features=15,
           forward=True,
           verbose=2,
           scoring='roc_auc',
           cv=4)


上のスクリプトでは、SequentialFeatureSelector関数に推定値として RandomForestClassifier を渡しています。

k_featuresは選択する素性の数を指定する。

ここでは、任意の個数の特徴を指定することができる。

forward パラメータは True に設定すると、ステップフォワード方式で特徴選択を行う。

また、verbose パラメータは特徴セレクタの処理状況をログに記録します。

scoring パラメータは性能評価基準を定義し、最後に cv はクロスバリデーションフォルダを参照します。

特徴セレクタを作成したら、次は fit メソッドを呼び出して、トレーニングセットとテストセットを渡します。

features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)


システムのハードウェアによっては、上記のスクリプトの実行に時間がかかることがあります。

上記スクリプトの実行が終了したら、以下のスクリプトを実行して、選択された15個の特徴を確認することができます。

filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features


出力には、以下の機能が表示されるはずです。

Index(['v4', 'v10', 'v14', 'v15', 'v18', 'v20', 'v23', 'v34', 'v38', 'v42',
       'v50', 'v51', 'v69', 'v72', 'v129'],
      dtype='object')


この15個の素性を使ったランダムフォレストアルゴリズムの分類性能を見るには、次のスクリプトを実行します。

clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)


train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))


test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))


上記のスクリプトでは、ステップフォワード特徴選択で選択した15個の特徴でランダムフォレストアルゴリズムを学習し、トレーニングセットとテストセットでアルゴリズムの性能を評価しています。

出力では、以下のような結果が得られるはずである。

Accuracy on training set: 0.7072327148174093
Accuracy on test set: 0.7096973252804142


トレーニングセットとテストセットでの精度はほぼ同じであり、モデルがオーバーフィットしていないことがわかります。

ステップバックワードフィーチャー選択

ステップ後退特徴選択とは、その名の通り、前節で検討したステップ前進特徴選択と正反対の特徴選択です。

ステップ後退特徴選択の最初のステップでは、特徴セットからラウンドロビン方式で1つの特徴を削除し、分類器の性能を評価します。

最も性能の良い特徴セットを保持する。

第二段階では、再びラウンドロビン方式で1つの特徴を取り除き、2つの特徴を除く全ての特徴の組み合わせの性能を評価する。

このプロセスは、データセットに指定された数の特徴が残るまで続けられる。

Pythonでステップ後方特徴量選択

本節では、BNP Paribas Cardif Claims Managementを対象に、ステップ・バックワード特徴選択を実装します。

前処理は前節と同じです。

唯一の変更は、SequentiaFeatureSelector クラスの forward パラメータです。

ステップバック型の特徴抽出を行う場合は、このパラメータを False に設定します。

以下のスクリプトを実行する。

from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from mlxtend.feature_selection import SequentialFeatureSelector


feature_selector = SequentialFeatureSelector(RandomForestClassifier(n_jobs=-1),
           k_features=15,
           forward=False,
           verbose=2,
           scoring='roc_auc',
           cv=4)


features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)


段階的解消の結果選択された素性を見るには、以下のスクリプトを実行する。

filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features


出力は以下のようになる。

Index(['v7', 'v8', 'v10', 'v17', 'v34', 'v38', 'v45', 'v50', 'v51', 'v61',
       'v94', 'v99', 'v119', 'v120', 'v129'],
      dtype='object')


最後に、段階的後退の結果選択された特徴量について、ランダムフォレスト分類器の性能を評価しましょう。

以下のスクリプトを実行してください。

clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)


train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))


test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))


出力はこのようになります。

Accuracy on training set: 0.7095207938140247
Accuracy on test set: 0.7114624676445211


トレーニングセットでの性能は、ステップフォワード特徴選択での性能と同様であることがわかります。

しかし、テストセットでは、後方特徴選択の方が若干性能が良い。

特徴量の網羅的な選択

網羅的特徴抽出では,機械学習アルゴリズムの性能をデータセット中の特徴の全ての可能な組み合わせに対して評価する.そして,最も良い性能を発揮する特徴量の部分集合が選択される.網羅的探索アルゴリズムは、特徴の全ての組み合わせを試し、最も良いものを選択するため、全てのラッパーの手法の中で最も貪欲なアルゴリズムである。

しかし、すべての特徴の組み合わせを評価するため、ステップフォワード法やステップバック法よりも処理速度が遅くなる可能性があります。

Pythonによる網羅的な特徴量の選択

ここでは、BNP Paribas Cardif Claims Managementを対象に、ステップ・バックワード型の特徴選択を実装します。

前処理は、ステップフォワード特徴選択と同様です。

網羅的な特徴選択を実装するために、mlxtend.feature_selection ライブラリの ExhaustiveFeatureSelector 関数を使用する予定です。

このクラスには min_featuresmax_features 属性があり、組み合わせの最小と最大の特徴数を指定することができる。

以下のスクリプトを実行してください。

from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from sklearn.metrics import roc_auc_score


feature_selector = ExhaustiveFeatureSelector(RandomForestClassifier(n_jobs=-1),
           min_features=2,
           max_features=4,
           scoring='roc_auc',
           print_progress=True,
           cv=2)


特徴セレクタを作成したら、次は fit メソッドをコールして、トレーニングセットとテストセットを渡します。

features = feature_selector.fit(np.array(train_features.fillna(0)), train_labels)


上のスクリプトの実行にはかなりの時間がかかることに注意してください。

ステップバック消去の結果、選択された特徴を見るには、次のスクリプトを実行します。

filtered_features= train_features.columns[list(features.k_feature_idx_)]
filtered_features


最後に、網羅的特徴抽出の結果選択された特徴量に対するランダムフォレスト分類器の性能を見るには、以下のスクリプトを実行します。

以下のスクリプトを実行してください。

clf = RandomForestClassifier(n_estimators=100, random_state=41, max_depth=3)
clf.fit(train_features[filtered_features].fillna(0), train_labels)


train_pred = clf.predict_proba(train_features[filtered_features].fillna(0))
print('Accuracy on training set: {}'.format(roc_auc_score(train_labels, train_pred[:,1])))


test_pred = clf.predict_proba(test_features[filtered_features].fillna(0))
print('Accuracy on test set: {}'.format(roc_auc_score(test_labels, test_pred [:,1])))


結論

ラッパー法は,特定の機械学習アルゴリズムの特徴抽出に使われる最も重要なアルゴリズムの一つである.この記事では,様々な種類のラッパーメソッドと,その実用的な実装を研究した.ステップフォワード法、ステップバック法、そして網羅的な特徴選択法について検討しました。

経験則として、データセットが小さい場合は網羅的特徴選択法を選択すべきですが、データセットが大きい場合は、ステップフォワードまたはステップバックワード特徴選択法を優先すべきです。

タイトルとURLをコピーしました