相関係数

Eval

相関係数

作成日: 最終更新: 読了時間: 2 分
まとめ
  • 相関係数は 2 つの変数の線形関係の強さと向きを測る代表的な指標です。
  • 散布図・相関行列・ヒートマップで可視化し、外れ値や非線形関係での落とし穴を確認します。
  • 相関と因果は別物であることを、共通要因による擬似相関の例とともに解説します。

1. 定義と性質 #

標本相関係数(ピアソンの積率相関係数)は、2 つの変数 \(x, y\) の共分散を標準偏差で正規化した値です。

$$ r = \frac{\sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_{i=1}^n (x_i - \bar{x})^2} , \sqrt{\sum_{i=1}^n (y_i - \bar{y})^2}} $$

  • \(-1 \le r \le 1\)
  • \(r > 0\):片方が大きくなるともう片方も増える直線的傾向
  • \(r < 0\):片方が大きくなるともう片方は減る傾向
  • \(|r| = 1\):完全な線形関係

線形関係の強さしか測れず、非線形なパターンや外れ値の影響を受けやすい点が課題です。


2. Python で相関係数を計算する #

import numpy as np

np.random.seed(777)
x = np.linspace(0, 100, 40) + np.random.rand(40)
y = np.linspace(1, 50, 40) + np.random.rand(40)

coef = np.corrcoef(x, y)
print(np.round(coef, 3))
import matplotlib.pyplot as plt

plt.figure(figsize=(5, 5))
plt.scatter(x, y)
plt.xlabel("x")
plt.ylabel("y")
plt.title("Scatter plot and correlation coefficient")
plt.grid(alpha=0.3)
plt.show()
線形関係を持つ 2 変数の散布図

相関係数は右肩上がりの散布図で 1 に近い値になる。

np.corrcoef が返す行列のオフ対角成分が相関係数です。散布図が右肩上がりで値が 1 に近い場合、強い正の相関と判断できます。


3. 複数変数の相関を俯瞰する #

import seaborn as sns

iris = sns.load_dataset("iris")
correlation = iris.corr(numeric_only=True)
correlation

pandas.DataFrame.corr で相関行列、Styler.background_gradient でヒートマップ表示が可能です。棒グラフにすると、どの変数と強く相関しているかが一目で分かります。

import matplotlib.pyplot as plt

correlation["sepal_length"].plot.bar(
    grid=True, ylabel="corr", color="#2563eb", title="Correlation with sepal_length"
)
plt.tight_layout()
plt.show()
アヤメデータの相関ヒートマップと棒グラフ

相関行列と棒グラフを併用すると、どの変数と強く相関しているかが把握しやすい。


4. 相関係数だけでは捉えられない関係 #

相関係数は線形性の指標であり、非線形構造やクラスター構造を持つデータでは値が小さくても明確なパターンが存在します。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

circle, _ = datasets.make_circles(n_samples=1_000, factor=0.1, noise=0.05, random_state=0)
moon, _ = datasets.make_moons(n_samples=1_000, noise=0.05, random_state=0)

def scatter_with_corr(ax, data, title):
    corr = np.corrcoef(data[:, 0], data[:, 1])[0, 1]
    ax.scatter(data[:, 0], data[:, 1], s=10, alpha=0.6)
    ax.set_title(f"{title}\ncorrelation={corr:.2f}")
    ax.set_xticks([])
    ax.set_yticks([])

fig, axes = plt.subplots(1, 2, figsize=(10, 4))
scatter_with_corr(axes[0], circle, "Concentric circles")
scatter_with_corr(axes[1], moon, "Moon-shaped data")
plt.tight_layout()
plt.show()
非線形構造を持つデータと相関係数

視覚的には明らかな関係でも、相関係数は 0 付近になりがち。

どちらも視覚的には明らかな関係がありますが、値は 0 付近となり「関係がない」と誤解されかねません。スピアマン相関や距離相関、相互情報量など他の指標も検討しましょう。


5. 相関と因果は異なる #

強い相関が観測されても、必ずしも片方がもう片方を引き起こしているとは限りません。同じ背景要因を共有しているだけの「擬似相関」や逆因果のケースが存在します。

下記の例では、季節性(共通の隠れ要因)によって変化する 2 つの数列が強い正の相関を示しますが、互いに因果関係はありません。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(123)
days = np.arange(365)
season = np.sin(2 * np.pi * days / 365)  # 季節を表す共通要因

ice_sales = 50 + 30 * season + np.random.normal(scale=5, size=days.size)
sunscreen_sales = 40 + 35 * season + np.random.normal(scale=6, size=days.size)

correlation = np.corrcoef(ice_sales, sunscreen_sales)[0, 1]
print(f"Correlation = {correlation:.3f}")

plt.figure(figsize=(6, 5))
plt.scatter(ice_sales, sunscreen_sales, alpha=0.6, s=18, color="#f97316")
plt.xlabel("Ice cream sales")
plt.ylabel("Sunscreen sales")
plt.title("Spurious correlation driven by the same seasonality")
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
季節性が生み出す擬似相関の散布図

共通の季節要因によってアイスクリームと日焼け止めの売上が同時に増える例。互いが互いを引き起こしているわけではない。

散布図は右上がりですが、両者を同時に増加させているのは「季節」という第三の要因です。

ポイント

  • 相関は因果を示さない(Correlation does not imply causation)。
  • 原因を推定したい場合は、実験デザイン・介入・統計的因果推論(DAG、傾向スコアなど)を適用する必要があります。
  • 変数間の関係を説明するときは、共通要因や時間の流れ、測定バイアスを必ずチェックしましょう。

6. 実務での活用と注意点 #

  • 前処理の参考:特徴選択や多重共線性の診断に相関係数を利用し、しきい値を決めて削減することがあります。
  • 外れ値の影響:単一の外れ値で値が大きく変わるため、散布図や箱ひげ図で併せて確認します。
  • 標本サイズ:サンプル数が少ないと推定誤差が大きくなるため、信頼区間や p 値も確認します。
  • 指標の組み合わせ:線形・非線形・ランク相関など複数の視点から分析し、モデル評価や説明に利用します。

まとめ #

  • 相関係数は 2 変数の線形な結び付きの強さと向きを示す基本指標です。
  • 非線形構造や外れ値の影響で誤解が生じるため、可視化と他指標の併用が不可欠です。
  • 強い相関があっても因果関係とは限らず、共通要因や時間の流れを踏まえて解釈しましょう。