pythonで相関係数を求めて可視化する方法|pandas・scipy・seaborn

pythonで相関係数を求めて可視化する方法|pandas・scipy・seaborn

実験やデータ分析で「どの条件が結果に大きく影響しているのか判断できない」「各条件の影響度をうまく説明できない」と悩むことはありますよね?そんなときに最初の手がかりになるのが相関係数です。

本記事では、pythonで相関係数を求めて可視化する方法を紹介します。計算にはpandasのcorr()(相関行列をまとめて求める)とscipyのpearsonr()(相関係数とp値を同時に求める)を、可視化にはseabornのヒートマップ(相関行列を色で見渡す)を使い、scikit-learnに付属する実データ(糖尿病データセット)で解説します。

この記事を読むことで、pythonで相関係数を求める方法と、結果から影響の大きい変数や似た変数を読み取る手順が分かります。

本記事のコードは全てグーグルコラボラトリーで記述・動作確認をしています。

構成と下書きに生成AIを使用し、コードの実行と検証は筆者が行っています。

目次

pythonで相関係数を求めて可視化する方法

pythonで相関係数を求めるにはpandasとscipy、結果を可視化するにはseabornを使います。

  • pandas.corr()(計算):データフレームの全列の組み合わせについて、相関係数をまとめて求める
  • scipy.stats.pearsonr()(計算):2つの変数の相関係数と、p値を同時に求める
  • seaborn.heatmap()(可視化):相関行列をヒートマップにして、色で全体を見渡す

計算と可視化は「どちらか一方を選ぶ」ものではなく、組み合わせて使うと効果的です。本記事では、目的変数との相関をpandasで求め、scipyでp値を確認し、seabornで全体を見渡したうえで、説明変数同士の似たペアを探して変数を絞り込むところまで進めます。全体の流れは次の図のとおりです。

相関係数で変数を絞り込む流れの図。目的変数との相関、p値の確認、ヒートマップ、似たペアを探す、残す変数を選ぶ、精度で確認の6段階で進む

環境準備とデータ読み込み|load_diabetes

今回は、scikit-learnに付属する糖尿病のデータセット(load_diabetes)を使います。年齢(age)、性別(sex)、BMI(bmi)、血圧(bp)、血液検査の値(s1〜s6)の10個の説明変数と、病気の進行度を表す目的変数(target)が入った公開データです。

「どの条件が結果に効いているか」を探すという点で、実験条件と測定結果の関係を調べる場面とよく似た構造になっています。

STEP
ライブラリのインポート

データの操作に使うpandasと、データセットを読み込むload_diabetesをインポートします。

import pandas as pd
from sklearn.datasets import load_diabetes
STEP
データの読み込み

as_frame=Trueを指定すると、データをpandasのデータフレームとして受け取れます。.frameで説明変数と目的変数(target)が1つにまとまった表を取り出し、head()で先頭5行を確認します。

df = load_diabetes(as_frame=True).frame
df.head()

出力:

スクロールできます
age sex bmi bp s1 s2 s3 s4 s5 s6 target
0 0.038076 0.050680 0.061696 0.021872 -0.044223 -0.034821 -0.043401 -0.002592 0.019907 -0.017646 151.0
1 -0.001882 -0.044642 -0.051474 -0.026328 -0.008449 -0.019163 0.074412 -0.039493 -0.068332 -0.092204 75.0
2 0.085299 0.050680 0.044451 -0.005670 -0.045599 -0.034194 -0.032356 -0.002592 0.002861 -0.025930 141.0
3 -0.089063 -0.044642 -0.011595 -0.036656 0.012191 0.024991 -0.036038 0.034309 0.022688 -0.009362 206.0
4 0.005383 -0.044642 -0.036385 0.021872 0.003935 0.015596 0.008142 -0.002592 -0.031988 -0.046641 135.0
STEP
データの大きさを確認

shapeで行数と列数を確認します。

df.shape

出力:

(442, 11)

行数は442、列数は11(説明変数10個と target)です。

STEP
基本統計量を確認

describe()で、列ごとの平均や標準偏差などをまとめて確認します。

df.describe()

出力:

スクロールできます
age sex bmi bp s1 s2 s3 s4 s5 s6 target
count 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 4.420000e+02 442.000000
mean -2.511817e-19 1.230790e-17 -2.245564e-16 -4.797570e-17 -1.381499e-17 3.918434e-17 -5.777179e-18 -9.042540e-18 9.293722e-17 1.130318e-17 152.133484
std 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 4.761905e-02 77.093005
min -1.072256e-01 -4.464164e-02 -9.027530e-02 -1.123988e-01 -1.267807e-01 -1.156131e-01 -1.023071e-01 -7.639450e-02 -1.260971e-01 -1.377672e-01 25.000000
25% -3.729927e-02 -4.464164e-02 -3.422907e-02 -3.665608e-02 -3.424784e-02 -3.035840e-02 -3.511716e-02 -3.949338e-02 -3.324559e-02 -3.317903e-02 87.000000
50% 5.383060e-03 -4.464164e-02 -7.283766e-03 -5.670422e-03 -4.320866e-03 -3.819065e-03 -6.584468e-03 -2.592262e-03 -1.947171e-03 -1.077698e-03 140.500000
75% 3.807591e-02 5.068012e-02 3.124802e-02 3.564379e-02 2.835801e-02 2.984439e-02 2.931150e-02 3.430886e-02 3.243232e-02 2.791705e-02 211.500000
max 1.107267e-01 5.068012e-02 1.705552e-01 1.320436e-01 1.539137e-01 1.987880e-01 1.811791e-01 1.852344e-01 1.335973e-01 1.356118e-01 346.000000

describe()の見どころ

age や bmi など説明変数の平均がほぼ0で、標準偏差がどれもほぼ同じ値(約0.048)になっています。load_diabetesの説明変数は、あらかじめ標準化(平均0にそろえてスケール調整)された状態で入っているためです。そのため、年齢が0.05のような不思議な値に見えます。一方、target だけは元のスケール(25〜346程度)のままです。

説明変数と target でスケールがまったく違いますが、相関係数を求めるうえでは問題ありません。

相関係数は単位やスケールの影響を受けないので、標準化された説明変数と元のスケールの target をそのまま比べられます。

実務の実験データでも、温度(℃)、時間(分)、濃度(%)のように単位がばらばらな条件を並べることがよくあります。相関係数なら、単位をそろえる前処理をしなくても関係の強さを同じ物差しで比べられるのが利点です。

相関係数をまとめて求める|pandas.corr()

まずはpandasのcorr()で、すべての列の組み合わせについて相関係数を求めます。データフレームに対して呼ぶだけで、相関行列(縦横に変数を並べた表)が返ってきます。特に指定しなければ、ピアソンの相関係数が計算されます。

STEP
相関行列を求める

df.corr()で、11列すべての組み合わせの相関係数を求めます。

df.corr()

出力:

スクロールできます
age sex bmi bp s1 s2 s3 s4 s5 s6 target
age 1.000000 0.173737 0.185085 0.335428 0.260061 0.219243 -0.075181 0.203841 0.270774 0.301731 0.187889
sex 0.173737 1.000000 0.088161 0.241010 0.035277 0.142637 -0.379090 0.332115 0.149916 0.208133 0.043062
bmi 0.185085 0.088161 1.000000 0.395411 0.249777 0.261170 -0.366811 0.413807 0.446157 0.388680 0.586450
bp 0.335428 0.241010 0.395411 1.000000 0.242464 0.185548 -0.178762 0.257650 0.393480 0.390430 0.441482
s1 0.260061 0.035277 0.249777 0.242464 1.000000 0.896663 0.051519 0.542207 0.515503 0.325717 0.212022
s2 0.219243 0.142637 0.261170 0.185548 0.896663 1.000000 -0.196455 0.659817 0.318357 0.290600 0.174054
s3 -0.075181 -0.379090 -0.366811 -0.178762 0.051519 -0.196455 1.000000 -0.738493 -0.398577 -0.273697 -0.394789
s4 0.203841 0.332115 0.413807 0.257650 0.542207 0.659817 -0.738493 1.000000 0.617859 0.417212 0.430453
s5 0.270774 0.149916 0.446157 0.393480 0.515503 0.318357 -0.398577 0.617859 1.000000 0.464669 0.565883
s6 0.301731 0.208133 0.388680 0.390430 0.325717 0.290600 -0.273697 0.417212 0.464669 1.000000 0.382483
target 0.187889 0.043062 0.586450 0.441482 0.212022 0.174054 -0.394789 0.430453 0.565883 0.382483 1.000000

対角線(自分自身との相関)はすべて1.000000になり、表は対角線を挟んで対称になります。

STEP
相関行列を変数に入れる

このあと何度も使うので、相関行列をcorr_matrixに入れておきます。

corr_matrix = df.corr()
STEP
目的変数との相関だけを取り出す

知りたいのは「どの説明変数が target と関係しているか」なので、target の列だけを取り出します。

corr_matrix['target']

出力:

target
age 0.187889
sex 0.043062
bmi 0.586450
bp 0.441482
s1 0.212022
s2 0.174054
s3 -0.394789
s4 0.430453
s5 0.565883
s6 0.382483
target 1.000000

変数s3が負の相関で、それ以外は正の相関です。s3は値が大きいほど target が小さくなる傾向がある、ということです。

STEP
絶対値で並べ替える

関係の強さは、正負に関係なく絶対値で比べます。abs()で絶対値にしてから、sort_values(ascending=False)で大きい順に並べます。

corr_matrix['target'].abs().sort_values(ascending=False)

出力:

target
target 1.000000
bmi 0.586450
s5 0.565883
bp 0.441482
s4 0.430453
s3 0.394789
s6 0.382483
s1 0.212022
age 0.187889
s2 0.174054
sex 0.043062

変数bmiが最も目的変数と相関が強そうです。

pandas.corr()の使いどころと注意点

corr()の強みは、1行で全組み合わせの相関がまとめて出ることです。最初に「どの変数が効いていそうか」を当たりをつける段階に向いています。

一方で、つまずきやすい点もあります。

  • abs()を付けずに並べると、s3(-0.394789)のような負の相関が下位に沈んでしまいます。強さを比べるときは絶対値、向きを確認するときは元の値、と使い分けます。
  • 並べ替えた結果の先頭には、target 自身(1.000000)が必ず来ます。説明変数の順位を見るときは、2行目から読みます。
  • corr()が返すのは相関係数だけで、その相関が偶然でないかどうか(p値)は分かりません。これを確認するのが次のscipyです。

相関係数とp値を求める|scipy.stats.pearsonr()

scipyのstats.pearsonr()を使うと、2つの変数の相関係数と、p値を同時に求められます。

STEP
scipyのインポート

scipyから統計関数をまとめたstatsをインポートします。

from scipy import stats
STEP
1つの変数で試す

まずは、最も相関が強かった bmi と target で試します。

stats.pearsonr(df['bmi'], df['target'])

出力:

PearsonRResult(statistic=np.float64(0.5864501344746887), pvalue=np.float64(3.4660064451669974e-42))

statisticが相関係数、pvalueがp値です。相関係数0.5864501344746887は、corr()で求めた bmi の値(0.586450)と一致しています。

STEP
全変数をfor文でまとめて計算する

pearsonr()は2変数ずつしか計算できないので、for文で target 以外の列を順番に回し、結果をリストにためてからデータフレームにします。pearsonr()の結果はcorrelation, p_valueのように2つの変数で受け取れます。

data_list = []
for col in df.columns:
    if col != 'target':
        correlation, p_value = stats.pearsonr(df['target'], df[col])
        data_list.append({'変数名':col, '相関係数':correlation, 'p値':p_value})
pearson_df = pd.DataFrame(data_list)
pearson_df

出力:

変数名 相関係数 p値
0 age 0.187889 7.055686e-05
1 sex 0.043062 3.664293e-01
2 bmi 0.586450 3.466006e-42
3 bp 0.441482 1.649372e-22
4 s1 0.212022 6.920712e-06
5 s2 0.174054 2.359848e-04
6 s3 -0.394789 6.162865e-18
7 s4 0.430453 2.304253e-21
8 s5 0.565883 8.826459e-39
9 s6 0.382483 7.580083e-17
STEP
相関係数の絶対値で並べる

相関係数の列だけを取り出し、絶対値の大きい順に並べます。

pearson_df['相関係数'].abs().sort_values(ascending=False)

出力:

相関係数
2 0.586450
8 0.565883
3 0.441482
7 0.430453
6 0.394789
9 0.382483
4 0.212022
0 0.187889
5 0.174054
1 0.043062

列を1つだけ取り出したため、変数名が消えて行番号(インデックス)だけになっています。2が bmi、8が s5 …と元の表と照らし合わせる必要があり、少し読みにくい形です。

STEP
p値が0.05より大きい変数を探す

条件を指定して、p値が0.05より大きい行を取り出します。

pearson_df[pearson_df['p値']>0.05]

出力:

変数名 相関係数 p値
1 sex 0.043062 0.366429

p値が0.05を超えたのは sex だけでした。sex は相関係数も0.043062と最も小さく、target との相関がゼロでないとは言えない変数です。

STEP
絶対値の列を追加して並べ替える

変数名が消えないように、絶対値を新しい列として追加します。

pearson_df['絶対値'] = pearson_df['相関係数'].abs()
pearson_df

出力:

変数名 相関係数 p値 絶対値
0 age 0.187889 7.055686e-05 0.187889
1 sex 0.043062 3.664293e-01 0.043062
2 bmi 0.586450 3.466006e-42 0.586450
3 bp 0.441482 1.649372e-22 0.441482
4 s1 0.212022 6.920712e-06 0.212022
5 s2 0.174054 2.359848e-04 0.174054
6 s3 -0.394789 6.162865e-18 0.394789
7 s4 0.430453 2.304253e-21 0.430453
8 s5 0.565883 8.826459e-39 0.565883
9 s6 0.382483 7.580083e-17 0.382483

追加した「絶対値」の列で並べ替え、reset_index(drop=True)で行番号を振り直します。

pearson_df.sort_values("絶対値", ascending=False).reset_index(drop=True)

出力:

変数名 相関係数 p値 絶対値
0 bmi 0.586450 3.466006e-42 0.586450
1 s5 0.565883 8.826459e-39 0.565883
2 bp 0.441482 1.649372e-22 0.441482
3 s4 0.430453 2.304253e-21 0.430453
4 s3 -0.394789 6.162865e-18 0.394789
5 s6 0.382483 7.580083e-17 0.382483
6 s1 0.212022 6.920712e-06 0.212022
7 age 0.187889 7.055686e-05 0.187889
8 s2 0.174054 2.359848e-04 0.174054
9 sex 0.043062 3.664293e-01 0.043062

変数名、相関係数(向き)、p値、絶対値(強さ)が1つの表にそろい、そのまま報告資料に貼れる形になりました。

p値と相関係数の違い

p値と相関係数は、見ているものが違います。

p値は「相関がゼロでないと言えるか」(偶然と考えにくいか)を、相関係数は「相関の強弱と向き」を示します。

たとえば今回の s2 は、相関係数が0.174054と小さめですが、p値は2.359848e-04で0.05を大きく下回っています。「相関がゼロではなさそう」ということと「相関が強い」ということは別の話です。p値が小さいからといって影響が大きいとは限らないので、まず相関係数で強さを見て、p値は偶然の可能性を除くための確認に使う、という順番で読むと混乱しません。

実務で上司や共同研究者に「この条件は効いているのか」と聞かれたとき、相関係数だけでなくp値も添えておくと、「たまたまそう見えているだけでは?」という質問に答えやすくなります。

相関行列を色で見渡す|seaborn.heatmap()

数値の表は、変数が10個を超えるとどこに注目すればよいか分かりにくくなります。そこで、seabornのheatmap()で相関行列を色付きの図にします。

STEP
ライブラリのインポート

描画に使うseabornとmatplotlibをインポートします。

import seaborn as sns
import matplotlib.pyplot as plt
STEP
ヒートマップを描く

pandasで求めたcorr_matrixをそのまま渡します。annot=Trueでマスの中に数値を表示し、fmt='.2f'で小数点以下2桁にそろえます。cmap='coolwarm'は正の相関を赤、負の相関を青で表す配色で、vmin=-1, vmax=1で色の範囲を-1〜1に固定しています。

plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True,
            fmt='.2f', cmap='coolwarm',
            vmin=-1, vmax=1)
plt.show()

出力:

糖尿病データセットの相関行列のヒートマップ。縦横に age から target までの11変数が並び、対角線を除くと、s1とs2のマスが0.90で最も濃い赤、s3とs4のマスが-0.74で最も濃い青になっている

ヒートマップの読み方

色の範囲を-1〜1に固定すると、中央の白が相関0に対応し、赤と青の濃さを同じ基準で読み取れます。この指定をしないと、データ内の最小値と最大値に合わせて色が割り当てられるため、弱い相関でも濃い色に見えてしまうことがあります。複数のデータセットのヒートマップを並べて比べるときにも、範囲を固定しておくと見比べやすくなります。

図で最も目立つのは s1-s2(0.90)のマスです。これは今回のデータでほぼ同じ情報を持つ変数のペアです。また、s3-s4(-0.74)の濃い青も目を引きます。

ここで気づくのが、target との相関だけを見ていては分からないことがあるという点です。pandasとscipyでは target の列だけに注目していましたが、ヒートマップでは説明変数同士の関係も一度に見えます。次の章では、この「説明変数同士の相関」を数値で取り出してみます。

実データで試す:似ている説明変数のペアを探す

ヒートマップで目立った s1-s2 のような「似た変数のペア」を、目で探すのではなくコードで一覧にします。説明変数が数十個になると、ヒートマップだけでは見落としが出るためです。

似た変数が両方入っていると、機械学習のモデルを作るときに同じ情報を二重に入れることになり、どちらの変数が効いているのかが解釈しにくくなります(多重共線性と呼ばれる問題です)。変数を絞り込む前の下調べとして、似たペアを洗い出しておきます。

STEP
target を除いた相関行列を作る

説明変数同士の相関だけを見たいので、drop()で target の行と列を取り除きます。

drop_target_corr = corr_matrix.drop(index='target', columns='target')
print(drop_target_corr)

出力:

          age       sex       bmi        bp        s1        s2        s3  \
age  1.000000  0.173737  0.185085  0.335428  0.260061  0.219243 -0.075181   
sex  0.173737  1.000000  0.088161  0.241010  0.035277  0.142637 -0.379090   
bmi  0.185085  0.088161  1.000000  0.395411  0.249777  0.261170 -0.366811   
bp   0.335428  0.241010  0.395411  1.000000  0.242464  0.185548 -0.178762   
s1   0.260061  0.035277  0.249777  0.242464  1.000000  0.896663  0.051519   
s2   0.219243  0.142637  0.261170  0.185548  0.896663  1.000000 -0.196455   
s3  -0.075181 -0.379090 -0.366811 -0.178762  0.051519 -0.196455  1.000000   
s4   0.203841  0.332115  0.413807  0.257650  0.542207  0.659817 -0.738493   
s5   0.270774  0.149916  0.446157  0.393480  0.515503  0.318357 -0.398577   
s6   0.301731  0.208133  0.388680  0.390430  0.325717  0.290600 -0.273697   

           s4        s5        s6  
age  0.203841  0.270774  0.301731  
sex  0.332115  0.149916  0.208133  
bmi  0.413807  0.446157  0.388680  
bp   0.257650  0.393480  0.390430  
s1   0.542207  0.515503  0.325717  
s2   0.659817  0.318357  0.290600  
s3  -0.738493 -0.398577 -0.273697  
s4   1.000000  0.617859  0.417212  
s5   0.617859  1.000000  0.464669  
s6   0.417212  0.464669  1.000000
STEP
numpyのインポート

重複を消すためのマスク(目隠し)を作るのにnumpyを使います。

import numpy as np
STEP
下三角のマスクを作る

相関行列は対角線を挟んで対称なので、同じペアが2回ずつ出てきます(age-sex と sex-age など)。また、対角線は自分自身との相関で必ず1になります。np.tril()で対角線を含む下三角をTrueにしたマスクを作り、これらを取り除く準備をします。

mask = np.tril(np.ones(drop_target_corr.shape), k=0).astype(bool)
mask

出力:

array([[ True, False, False, False, False, False, False, False, False,
        False],
       [ True,  True, False, False, False, False, False, False, False,
        False],
       [ True,  True,  True, False, False, False, False, False, False,
        False],
       [ True,  True,  True,  True, False, False, False, False, False,
        False],
       [ True,  True,  True,  True,  True, False, False, False, False,
        False],
       [ True,  True,  True,  True,  True,  True, False, False, False,
        False],
       [ True,  True,  True,  True,  True,  True,  True, False, False,
        False],
       [ True,  True,  True,  True,  True,  True,  True,  True, False,
        False],
       [ True,  True,  True,  True,  True,  True,  True,  True,  True,
        False],
       [ True,  True,  True,  True,  True,  True,  True,  True,  True,
         True]])
STEP
上三角だけを残す

where()は条件がTrueの場所だけ値を残し、それ以外を欠損値にします。~maskでマスクを反転させているので、対角線より上(上三角)だけが残ります。

upper_corr = drop_target_corr.where(~mask)
STEP
縦長の表に変換する

stack()で行列を「変数A、変数B、相関係数」の縦長の表に変換します。欠損値になった下三角は、このとき取り除かれます。

stacked_corr = upper_corr.stack().reset_index()
stacked_corr.columns = ['variable_A', 'variable_B', 'correlation']
print(stacked_corr)

出力:

   variable_A variable_B  correlation
0         age        sex     0.173737
1         age        bmi     0.185085
2         age         bp     0.335428
3         age         s1     0.260061
4         age         s2     0.219243
(中略)
30         s1         s2     0.896663
31         s1         s3     0.051519
32         s1         s4     0.542207
33         s1         s5     0.515503
34         s1         s6     0.325717
35         s2         s3    -0.196455
36         s2         s4     0.659817
37         s2         s5     0.318357
38         s2         s6     0.290600
39         s3         s4    -0.738493
40         s3         s5    -0.398577
41         s3         s6    -0.273697
42         s4         s5     0.617859
43         s4         s6     0.417212
44         s5         s6     0.464669

10個の説明変数から2つを選ぶ組み合わせ、45ペア(0〜44)が重複なく並びました。

STEP
絶対値で並べて上位を確認する

負の相関も「似ている」に含めたいので、絶対値の列を追加してから大きい順に並べ、上位5ペアを表示します。

stacked_corr['abs_corr'] = stacked_corr['correlation'].abs()
top_pairs = stacked_corr.sort_values(by='abs_corr', ascending=False)
top_pairs.head(5).reset_index(drop=True)

出力:

variable_A variable_B correlation abs_corr
0 s1 s2 0.896663 0.896663
1 s3 s4 -0.738493 0.738493
2 s2 s4 0.659817 0.659817
3 s4 s5 0.617859 0.617859
4 s1 s4 0.542207 0.542207

結果の読み取りと変数の絞り方

ここまでの結果を整理すると、次のようになります。

  • 関係が強そうな変数:target との相関は bmi(0.59)、s5(0.57)、bp(0.44)が上位
  • 似た変数:s1-s2(0.90)は特に近く、s3-s4(-0.74)は向きが逆でも情報が重なる
  • 相関がゼロと言えない変数:p値が0.05を超えたのは sex だけ

s3-s4 は相関係数がマイナスですが、「片方が大きいともう片方が小さい」という関係がはっきりしているので、一方の値からもう一方をある程度推測できます。向きが逆でも、情報が重なっている点は s1-s2 と同じです。

似たペアは、target との相関が高いほうを残すのが基本です。たとえば s1 と s2 なら、target との相関は s1 が0.212022、s2 が0.174054なので、s1 を残します。

ただし、相関だけで決めず、落としても精度が変わらないかを確認します。相関係数は2つの変数の直線的な関係しか見ていないため、他の変数と組み合わせたときにどう働くかまでは分かりません。実際にモデルを作り、変数を外す前と後で精度を比べてから判断するのが安全です。

  1. pandas.corr()で target との相関を求め、絶対値で並べる
  2. scipy.stats.pearsonr()でp値を確認し、相関がゼロと言えない変数を把握する
  3. seaborn.heatmap()で全体を見渡し、説明変数同士の似たペアに気づく
  4. 上三角を取り出して似たペアを一覧にし、target との相関が高いほうを残す
  5. 変数を落としても精度が変わらないかを確認する

計算(pandas・scipy)と可視化(seaborn)の比較

計算に使うpandas・scipyと、可視化に使うseabornを、実務での使いどころの観点で比べます。

方法 得られるもの 向いている場面 注意点
pandas.corr() 全組み合わせの相関係数(相関行列) 最初に全体の当たりをつける p値は出ない
scipy.stats.pearsonr() 2変数の相関係数とp値 偶然でないかを確認し、報告用の表を作る 2変数ずつなので、全変数を調べるにはfor文が必要
seaborn.heatmap() 相関行列の図 説明変数同士も含めて全体を見渡す、人に説明する 色の範囲を-1〜1に固定しないと濃さを比べにくい

pandasとseabornは、corr_matrixを作れば続けて使えるので相性がよい組み合わせです。scipyはコードが少し長くなりますが、「その相関は偶然では?」に答える材料が手に入ります。

実際に試して感じたこと

実際にコードを動かしてみて、筆者が感じたことをまとめます。

  • つまずいたところ、出たエラー: データの処理につまずきました。for文が難しかったです。
  • 意外だったこと: 目的変数との相関の他に、説明変数同士の相関も見て考える必要があると気づきました。
  • 実務ならどの方法を使うか: seaborn
  • 初心者へのひとこと: データを可視化することで気づくことがあります。相関係数が高いからといって、必ずしも要因であるとは限らないので注意してください。

for文でつまずきやすいのは、scipy.stats.pearsonr()で全変数の相関係数とp値をまとめて計算するSTEPです。target 自身を除く条件(if col != 'target')、結果を辞書にしてリストにためる処理、最後にデータフレームにする処理が一度に出てくるので、つまずいたときは1行ずつprint()しながら確かめると理解しやすくなります。

説明変数同士の相関は、ヒートマップの章で s1-s2(0.90)や s3-s4(-0.74)として目立っていた関係です。pandasやscipyで target の列だけを数値で見ていると、この関係は見えません。

まとめ

本記事では、pythonで相関係数をpandasとscipyで求め、seabornで可視化する方法を紹介しました。

  • pandas.corr()(計算):1行で相関行列を求められる。abs()とsort_values()で target との相関の強い順に並べられる
  • scipy.stats.pearsonr()(計算):相関係数とp値を同時に求められる。for文で全変数をまとめて計算し、表にできる
  • seaborn.heatmap()(可視化):相関行列を色で見渡せる。説明変数同士の似たペアにも気づける

おすすめは seaborn.heatmap() です。

corr()で相関行列を作るところまではpandasの1行で済み、そこからheatmap()に渡すだけで、target との関係と説明変数同士の関係を一度に見渡せます。今回のデータでも、ヒートマップで最も目立つのは s1-s2 の強い相関でした。数値で詳しく確かめたいときや、報告用にp値を添えたいときはscipyを組み合わせてください。

ただし、相関係数が高いからといって、その変数が必ずしも要因であるとは限りません。相関係数は「どの条件から詳しく調べるか」の優先順位を決める道具として使い、最終的な判断は、変数を落としたときの精度の変化や、実験・現場の知見と合わせて行うのがおすすめです。

よくある質問

pythonで相関係数を求める一番簡単な方法は?

pandasのデータフレームに対してcorr()を呼ぶのが一番簡単です。全列の組み合わせの相関係数が相関行列としてまとめて返ってきます。目的変数との相関だけを見たいときは、corr_matrix['target']のように列を取り出します。

相関係数とp値はどう使い分ければよいですか?

相関係数は「相関の強弱と向き」、p値は「相関がゼロでないと言えるか」を示します。まず相関係数で強さを見て、p値で偶然の可能性を除く、という順番で読むと混乱しません。p値はscipy.stats.pearsonr()で求められます。

負の相関はどう扱えばよいですか?

関係の強さを比べるときは、abs()で絶対値にしてから並べます。そのまま並べると、強い負の相関が下位に沈んでしまいます。向きを確認したいときは、元の値も合わせて見てください。

ヒートマップでvmin=-1, vmax=1を指定するのはなぜですか?

色の範囲を-1〜1に固定すると、中央の白が相関0に対応し、赤と青の濃さを同じ基準で読み取れるからです。指定しないと、データ内の最小値と最大値に合わせて色が割り当てられます。

相関係数が高い変数が原因だと考えてよいですか?

相関係数が高いからといって、必ずしも要因であるとは限りません。また、似た説明変数のペアがある場合は、target との相関が高いほうを残したうえで、変数を落としても精度が変わらないかを確認することが大切です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次