AIって結局何なのかよく分からないので、とりあえず100日間勉強してみた Day28
経緯についてはこちらをご参照ください。
■本日の進捗
●モデルベース特徴量選択を理解
■はじめに
引き続き「Pythonではじめる機械学習(オライリー・ジャパン)」で学んでいきます。
これまでは特徴量を増やして(ある種学習モデルの複雑度を増して)精度向上を計る手法を経験してきました。しかし高次元データセットであればどの特徴量が重要なものなのかが分かればそれだけを用いてモデルを学習させることができ、汎化性能も向上しそうに思えます。
今回は自動的に重要度の高い特徴量を選択し学習させることのできる自動特徴量選択手法から、モデルベース特徴量選択を学んでいきます。
■モデルベース特徴量選択
モデルベース特徴量選択(model-based feature selection)とは、任意のアルゴリズムで学習をさせる前に教師あり学習モデルで事前に特徴量を学習させて、与えた特徴量の中から重要なものだけを予め選択して次元削減を行う手法です。
この手法で用いる教師あり学習モデルは最終的に用いるアルゴリズムに関係なく自由に選択できるのですが、特徴量ごとに重要度の情報(重み、係数)を付加できる機械学習モデルでなければいけません。
良く用いられるのはリッジ回帰、Lasso回帰、サポートベクターマシンなどの正規化項を持つモデルや、自動的に重要度の情報(feature_importance_)を持つランダムフォレストや勾配ブースティング回帰木などがあります。
まずは4つの特徴量を持つあやめデータセットに大量のノイズデータを新たな特徴量として追加し、ロジスティック回帰で学習させてみます。
import numpy as np import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression iris = load_iris() X = pd.DataFrame(iris.data, columns=iris.feature_names) y = iris.target np.random.seed(8) for i in range(88): X[f'noise_feature_{i+1}'] = np.random.rand(X.shape[0]) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=8) model = LogisticRegression(max_iter=1000, random_state=8) model.fit(X_train, y_train) score = model.score(X_test, y_test) print("score is ", score)
score is 0.8444444444444444
スコアは上記の通りでした。ここからランダムフォレストを用いたモデルベース特徴量選択を行った後に再度ロジスティック回帰で学習させてみます。
import numpy as np import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.feature_selection import SelectFromModel iris = load_iris() X = pd.DataFrame(iris.data, columns=iris.feature_names) y = iris.target np.random.seed(8) for i in range(88): X[f'noise_feature_{i+1}'] = np.random.rand(X.shape[0]) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=8) rf_model = RandomForestClassifier(random_state=8) rf_model.fit(X_train, y_train) selector = SelectFromModel(rf_model, threshold="mean") selector.fit(X_train, y_train) X_train_selected = selector.transform(X_train) X_test_selected = selector.transform(X_test) model = LogisticRegression(max_iter=1000, random_state=8) model.fit(X_train_selected, y_train) score = model.score(X_test_selected, y_test) print("score is", score)
score is 0.9111111111111111
同じロジスティック回帰ですが、モデルの予測精度が大きく向上しています。これは恐らく追加した大量のノイズ特徴量の多くが除外されたのでしょう。
各特徴量の重要度も表示可能なので見てみましょう。
importances = rf_model.feature_importances_ for feature, importance in zip(X_train.columns, importances): print(f"{feature}: {importance:.4f}")
sepal length (cm): 0.0944
sepal width (cm): 0.0528
petal length (cm): 0.1574
petal width (cm): 0.1681
noise_feature_1: 0.0075
noise_feature_2: 0.0028
noise_feature_3: 0.0080
noise_feature_4: 0.0061
noise_feature_5: 0.0086
noise_feature_6: 0.0080
noise_feature_7: 0.0036
noise_feature_8: 0.0036
noise_feature_9: 0.0067
noise_feature_10: 0.0066
noise_feature_11: 0.0137
noise_feature_12: 0.0040
noise_feature_13: 0.0015
noise_feature_14: 0.0014
noise_feature_15: 0.0054
noise_feature_16: 0.0076
noise_feature_17: 0.0031
noise_feature_18: 0.0063
noise_feature_19: 0.0118
noise_feature_20: 0.0086
noise_feature_21: 0.0041
noise_feature_22: 0.0037
noise_feature_23: 0.0072
noise_feature_24: 0.0037
noise_feature_25: 0.0030
noise_feature_26: 0.0074
noise_feature_27: 0.0054
noise_feature_28: 0.0071
noise_feature_29: 0.0058
noise_feature_30: 0.0047
noise_feature_31: 0.0021
noise_feature_32: 0.0131
noise_feature_33: 0.0126
noise_feature_34: 0.0151
noise_feature_35: 0.0057
noise_feature_36: 0.0036
noise_feature_37: 0.0079
noise_feature_38: 0.0095
noise_feature_39: 0.0050
noise_feature_40: 0.0107
noise_feature_41: 0.0064
noise_feature_42: 0.0051
noise_feature_43: 0.0048
noise_feature_44: 0.0050
noise_feature_45: 0.0058
noise_feature_46: 0.0033
noise_feature_47: 0.0047
noise_feature_48: 0.0044
noise_feature_49: 0.0088
noise_feature_50: 0.0030
noise_feature_51: 0.0094
noise_feature_52: 0.0078
noise_feature_53: 0.0043
noise_feature_54: 0.0044
noise_feature_55: 0.0111
noise_feature_56: 0.0041
noise_feature_57: 0.0064
noise_feature_58: 0.0027
noise_feature_59: 0.0070
noise_feature_60: 0.0043
noise_feature_61: 0.0049
noise_feature_62: 0.0039
noise_feature_63: 0.0025
noise_feature_64: 0.0053
noise_feature_65: 0.0085
noise_feature_66: 0.0020
noise_feature_67: 0.0033
noise_feature_68: 0.0049
noise_feature_69: 0.0056
noise_feature_70: 0.0091
noise_feature_71: 0.0133
noise_feature_72: 0.0078
noise_feature_73: 0.0047
noise_feature_74: 0.0062
noise_feature_75: 0.0039
noise_feature_76: 0.0046
noise_feature_77: 0.0034
noise_feature_78: 0.0048
noise_feature_79: 0.0026
noise_feature_80: 0.0110
noise_feature_81: 0.0060
noise_feature_82: 0.0048
noise_feature_83: 0.0061
noise_feature_84: 0.0060
noise_feature_85: 0.0085
noise_feature_86: 0.0023
noise_feature_87: 0.0049
noise_feature_88: 0.0014
ノイズ特徴量はそのほとんどが0.01未満の重要度しかなく、モデルベース特徴量選択によって重要ではない特徴量だと判断されたことになります。それに対して元々存在する特徴量4つはどれも重要度0.05以上です。
■おわりに
構築したいモデルとは全く違うモデル(ランダムフォレスト)でモデルベース特徴量選択を行った結果、多くのノイズ特徴量を重要ではないと判断して取り除いてくれました。これは現実のデータ(作為的に追加したノイズデータではなく)の場合でも、重要ではないと判断された特徴量は落ち、モデルが学習する上で重要だった特徴量を(可能な限り)残した状態で学習を開始できます。
■参考文献
- Andreas C. Muller, Sarah Guido. Pythonではじめる機械学習. 中田 秀基 訳. オライリー・ジャパン. 2017. 392p.
- ChatGPT. 4o mini. OpenAI. 2024. https://chatgpt.com/
- API Reference. scikit-learn.org. https://scikit-learn.org/stable/api/index.html