pythonで高相関の特徴量を削除する方法

重回帰モデルなどの予測モデル構築を行う際に,特徴量間で高い相関係数を示すものが存在する場合には多重共線性が問題となるケースがあります。

こうしたケースでは一般的に高相関の特徴量をデータから除外しますが,このページではその手続きについて説明します。

パッケージの読み込み

ここでは以下のパッケージを用います。

# データ処理
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer

# グラフ描画
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns

サンプルデータの読み込み

ここではサンプルデータとして,scikit-learnのbreast_cancerデータセットを用います。下図にある通り,30個の特徴量が存在します。

# サンプルデータのインスタンスを生成
cancer = load_breast_cancer()

# 特徴量をデータフレームに変換
X = pd.DataFrame(cancer.data,
                 columns=cancer.feature_names)

display(X)

特徴量間の相関係数を可視化する

まずは全ての特徴量間の相関係数を可視化してみます。先ほどpandas.DataFrameとして読み込んだデータの相関係数の行列(X.corr())を,seaborn.heatmapに渡すことでヒートマップとして可視化しています。

ヒートマップとカラーバーから読み取れるように,いくつかの特徴量の間で相関係数=0.95を超えるものが存在しそうです。

# グラフ描画領域の作成
plt.figure(figsize=(15, 15))

# 相関係数のヒートマップを描画
sns.heatmap(X.corr(),
            cmap='jet',
            square=True,
            linewidths=0.1,
            vmax=1,
            vmin=-1,
            center=0)

plt.show()

高い相関係数を示す特徴量の名称を取得する

高相関係数を示す特徴量の特徴量名を,以下の手順で取得していきます。

  1. 相関係数は-1から1の値をとるので,その絶対値を求める(corr_matrix)
  2. 計算処理削減と抽出される特徴量名の重複を避けるため,正方行列:corr_matrixの上側三角行列を抽出する(upper)
  3. 上側三角行列の各列に対して,指定した相関係数の削除基準を超過する値があれば,その列名をリストに加える(list_drop)
# 相関係数の削除基準
criterion = 0.95

# 相関係数行列の絶対値を取得
corr_matrix = X.corr().abs()

# 上三角行列を取得
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))

# 指定域以上の相関係数の絶対値を有する列名をリストに格納
list_drop = [column for column in upper.columns if any(upper[column] > criterion)]

# 削除対象の列名一覧
display(list_drop)
削除対象の列名一覧

['mean perimeter',
 'mean area',
 'perimeter error',
 'area error',
 'worst radius',
 'worst perimeter',
 'worst area']

高相関特徴量を除外する

元のデータフレーム(X)から,作成した削除対象の列名(list_drop)をdropさせることで高相関特徴量をデータから除外しています。

元のデータセット(X)は30特徴量でしたが,新しいデータセット(X_dropped)は高い相関係数を示す特徴量が除かれて23特徴量になっています。

# 特徴量の削除
X_dropped = X.drop(list_drop, axis=1)

display(X_dropped)

特徴量除外後の特徴量間の相関係数を可視化する

高い相関係数を示す特徴量を除外したデータセットにおける特徴量間の相関係数を,先ほど同様にヒートマップ形式で可視化します。

ヒートマップ内に示されている通り,相関係数=0.95を超過する特徴量がデータセットから取り除かれていることがわかります。

# グラフ描画領域の作成
plt.figure(figsize=(15, 15))

# 相関係数のヒートマップを描画
sns.heatmap(X_dropped.corr(),
            cmap='jet',
            square=True,
            linewidths=0.1,
            vmax=1,
            vmin=-1,
            center=0,
            annot=True)

plt.show()

特定の特徴量をデータセットに残す場合

ここまでの処理で,高い相関係数を示す特徴量をデータセットから取り除くことができました。しかし,このままでは高い相関係数を示す「全て」の特徴量が取り除かれてしまっています。

多重共線性の問題を回避するためには,高い相関係数を示す特徴量の組の一方を取り除けばいいのですが,これまでの処理では特徴量の組そのものがデータセットから除外されてしまっています。

そこで,除外対象の特徴量名称リストから,特定の特徴量名称を外すことで特徴量をデータに残す必要があります。ここでは適当に「worst concave points」特徴量をデータセットに残します(実際の解析では残すべき特徴量をよく吟味する必要があります)。

# ドロップする列名のリストから残したい列名を外す
list_drop.remove('worst concave points')

# 新しいlist_dropに従い特徴量を削除
X_dropped = X.drop(list_drop, axis=1)

# グラフ描画領域の作成
plt.figure(figsize=(15, 15))

# 相関係数のヒートマップを描画
sns.heatmap(X_dropped.corr(),
            cmap='jet',
            square=True,
            linewidths=0.1,
            vmax=1,
            vmin=-1,
            center=0,
            annot=True)

plt.show()

最後に

以上の処理で,多重共線性の問題を引き起こしかねない特徴量をデータセットから取り除くことができました。ここでは特定の基準値で機械的に除外する特徴量を決定し,適当な特徴量を除外対象から外しましたが,実際の解析ではデータ性質等を考慮して残すべき特徴量・外すべき特徴量を決める必要があります。

また今回の処理では,2変数間の相関係数を対象に除外処理を行いましたが,これだけでは多重共線性の問題を回避するのには十分ではない点にも注意が必要です。多変数間の関係で多重共線性が生じる可能性がありますので,実解析ではVIF基準の値を確認することも検討してください。

ソースコードはこちら

コメント