特徴量重要度による特徴量選定の実装　-LightGBMモデル

# はじめに

近年、機械学習の分野では特徴量選定（Feature Selection）が重要な技術として注目されています。特徴量選定は、モデルの学習に使用する特徴量を適切に選ぶことで、モデルの性能向上や過学習の防止につながります。特に、特徴量の重要度に基づいて選定を行う手法は、モデルの理解や解釈性の向上にも役立ちます。

#  特徴量重要度による特徴量選定について

特徴量重要度による特徴量選定は、機械学習モデルが各特徴量の重要度を算出し、その重要度に基づいて特徴量を選択する手法です。特に、決定木ベースのアルゴリズムでは、各特徴量の分岐における重要度を計算することが一般的です。LightGBMは、勾配ブースティングに基づくツリー学習アルゴリズムであり、特徴量の重要度を高速かつ効果的に計算することができるため、特徴量選定において優れた性能を発揮します。

#  今回の実装内容

今回は、Pythonの機械学習ライブラリであるscikit-learnとLightGBMを使用して、特徴量重要度に基づく特徴量選定を実装しました。具体的には、RFE（Recursive Feature Elimination）アルゴリズムを使用し、LightGBMモデルを学習器として選定を行いました。RFEアルゴリズムは、反復的に最も重要でない特徴量を削除し、目標とする特徴量数に到達するまで繰り返し学習を行う手法です。

```python:sample.py
import pandas as pd
import numpy as np
from sklearn.metrics import precision_score, recall_score
from sklearn.feature_selection import RFE
from lightgbm import LGBMClassifier
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

def under_sample(X, y, random_state=None):
    # 下サンプリング：正例の数を負例と同じ数にする
    X_pos = X[y == 1]
    X_neg = X[y == 0]
    np.random.seed(random_state)
    random_indices = np.random.choice(len(X_neg), size=len(X_pos), replace=False)
    X_neg_under_sampled = X_neg[random_indices]
    X_under_sampled = np.concatenate([X_pos, X_neg_under_sampled])
    y_under_sampled = np.concatenate([np.ones(len(X_pos)), np.zeros(len(X_pos))])
    return X_under_sampled, y_under_sampled

def plot_evaluation_metrics(num_features_list, precision_list, recall_list, save_path=None):
    # 特徴量の数と評価指標の関係を示す曲線を描画
    plt.plot(num_features_list, precision_list, label='Precision')
    plt.plot(num_features_list, recall_list, label='Recall')
    plt.xlabel('特徴量の数')
    plt.ylabel('スコア')
    plt.title('評価指標 vs. 特徴量の数')
    plt.legend()
    if save_path:
        plt.savefig(save_path)
    plt.show()

def plot_feature_importance(feature_importance, feature_names, top_n=30, save_path=None):
    # 上位 top_n 個の重要な特徴量を抽出
    sorted_indices = np.argsort(feature_importance)[::-1][:top_n]
    sorted_features = feature_names[sorted_indices]
    sorted_importance = feature_importance[sorted_indices]

    # 特徴量の重要度を示すグラフを描画
    plt.figure(figsize=(10, 6))
    plt.barh(range(top_n), sorted_importance, align='center')
    plt.yticks(range(top_n), sorted_features)
    plt.xlabel('特徴量の重要度')
    plt.ylabel('特徴量')
    plt.title('上位30個の特徴量の重要度')
    plt.gca().invert_yaxis()
    if save_path:
        plt.savefig(save_path)
    plt.show()

def feature_selection(model, dataframe, num_target):
    X = dataframe.drop(columns=['target']).values
    y = dataframe['target'].values

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    num_features_list = []
    precision_list = []
    recall_list = []
    feature_names_list = []

    feature_importance_list = []

    for i in range(dataframe.shape[1] - 1, num_target - 1, -1):
        X_under_sampled, y_under_sampled = under_sample(X_train, y_train, random_state=42)
        rfe = RFE(estimator=model, n_features_to_select=i)
        rfe.fit(X_under_sampled, y_under_sampled)
        selected_features = np.where(rfe.support_)[0]
        feature_names = dataframe.drop(columns=['target']).columns[selected_features]
        feature_names_list.append(feature_names)
        X_selected = X_under_sampled[:, selected_features]

        model.fit(X_selected, y_under_sampled)
        y_pred = model.predict(X_test[:, selected_features])
        precision = precision_score(y_test, y_pred)
        recall = recall_score(y_test, y_pred)

        num_features_list.append(i)
        precision_list.append(precision)
        recall_list.append(recall)

        feature_importance_list.append(model.feature_importances_)

        # 各回のトップ30の特徴量の重要度グラフを描画
        plot_feature_importance(model.feature_importances_, feature_names, top_n=30, save_path=f"feature_importance_iter_{dataframe.shape[1]-i}.png")

    plot_evaluation_metrics(num_features_list, precision_list, recall_list, save_path="evaluation_metrics_curve.png")
    return num_features_list, precision_list, recall_list, feature_names_list, feature_importance_list

# 使用例
dataframe = pd.DataFrame(data=X_train, columns=[f'feature_{i}' for i in range(X_train.shape[1])])
dataframe['target'] = y_train

lgb_model = LGBMClassifier()
num_features_list, precision_list, recall_list, feature_names_list, feature_importance_list = feature_selection(lgb_model, dataframe, num_target=200)

```

#  工夫したところ

今回の実装では、以下の点に工夫を凝らしました。

モデルの学習にはLightGBMを使用し、高速で効率的な特徴量重要度の計算を実現しました。
RFEアルゴリズムを用いて、目標とする特徴量数に達するまで反復的に特徴量選定を行うことで、最適な特徴量セットを見つける効率を向上させました。
#  おわりに

特徴量重要度に基づく特徴量選定は、機械学習モデルの性能向上や解釈性の向上に役立つ重要な手法です。LightGBMを使用した今回の実装では、効率的かつ効果的に特徴量選定を行い、モデルの性能向上に貢献しました。今後も、特徴量選定の手法を研究し、さまざまな問題に適用していきたいと考えています。