- 相関係数は 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()

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