分散共分散行列(共分散行列)は、統計学や機械学習の分野で頻出の概念No.1といえるほどの重要な統計量です。
特に多変量のデータを扱う際には、この分散共分散行列をどのように扱うかが、解析の鍵となることが多いでしょう。今回はこの分散共分散行列を1から紐解いていきます。
本記事の内容
- 分散と共分散の復習
- 分散共分散行列の定義と直感的な意味
- 共分散行列の性質(半正定値性、固有値分解)
- Pythonでの計算と可視化
分散の復習
分散共分散行列を理解するために、まず1変量の分散から復習しましょう。
確率変数 $X$ の分散(Variance)は、データの散らばり具合を測る指標で、以下のように定義されます。
$$ \text{Var}(X) = E[(X – \mu_X)^2] $$
ここで $\mu_X = E[X]$ は $X$ の期待値(平均)です。$n$ 個のデータ $x_1, x_2, \dots, x_n$ に対する標本分散は以下で計算されます。
$$ s_X^2 = \frac{1}{n-1} \sum_{i=1}^{n} (x_i – \bar{x})^2 $$
共分散の復習
2つの確率変数 $X$, $Y$ の共分散(Covariance)は、2変数間の線形的な関係の強さと方向を測る指標です。
$$ \text{Cov}(X, Y) = E[(X – \mu_X)(Y – \mu_Y)] $$
標本共分散は以下で計算されます。
$$ s_{XY} = \frac{1}{n-1} \sum_{i=1}^{n} (x_i – \bar{x})(y_i – \bar{y}) $$
共分散の符号には以下の意味があります。
- $\text{Cov}(X, Y) > 0$: $X$ が大きいとき $Y$ も大きい傾向(正の相関)
- $\text{Cov}(X, Y) < 0$: $X$ が大きいとき $Y$ は小さい傾向(負の相関)
- $\text{Cov}(X, Y) = 0$: 線形的な関係がない(無相関)
また、$\text{Cov}(X, X) = \text{Var}(X)$ であることに注意してください。
分散共分散行列の定義
$d$ 次元の確率変数ベクトル $\bm{x} = (X_1, X_2, \dots, X_d)^T$ に対して、分散共分散行列(Covariance Matrix)$\bm{\Sigma}$ は、全てのペアの共分散を行列にまとめたものです。
$$ \bm{\Sigma} = \text{Cov}(\bm{x}) = E[(\bm{x} – \bm{\mu})(\bm{x} – \bm{\mu})^T] $$
成分で書くと、
$$ \bm{\Sigma} = \begin{pmatrix} \text{Var}(X_1) & \text{Cov}(X_1, X_2) & \cdots & \text{Cov}(X_1, X_d) \\ \text{Cov}(X_2, X_1) & \text{Var}(X_2) & \cdots & \text{Cov}(X_2, X_d) \\ \vdots & \vdots & \ddots & \vdots \\ \text{Cov}(X_d, X_1) & \text{Cov}(X_d, X_2) & \cdots & \text{Var}(X_d) \end{pmatrix} $$
対角成分は各変数の分散、非対角成分は変数間の共分散です。$\text{Cov}(X_i, X_j) = \text{Cov}(X_j, X_i)$ なので、共分散行列は対称行列になります。
共分散行列の性質
共分散行列は以下の重要な性質を持ちます。
- 対称行列: $\bm{\Sigma} = \bm{\Sigma}^T$
- 半正定値: 任意のベクトル $\bm{v}$ に対して $\bm{v}^T \bm{\Sigma} \bm{v} \ge 0$
- 固有値は全て非負: 半正定値性から、全ての固有値 $\lambda_i \ge 0$
- 対角化可能: 対称行列なので直交行列で対角化できる
半正定値性は、分散が常に非負であることから導かれます。任意の $\bm{v}$ に対して、
$$ \bm{v}^T \bm{\Sigma} \bm{v} = \text{Var}(\bm{v}^T \bm{x}) \ge 0 $$
Pythonでの計算
2次元のデータを生成し、共分散行列を計算・可視化してみましょう。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
# 2次元の多変量正規分布からデータを生成
mean = [2, 3]
cov_true = [[4, 2.5],
[2.5, 3]]
data = np.random.multivariate_normal(mean, cov_true, size=300)
# 標本共分散行列の計算
cov_sample = np.cov(data.T)
print("真の共分散行列:")
print(np.array(cov_true))
print("\n標本共分散行列:")
print(cov_sample.round(3))
# 可視化
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 左: 散布図
axes[0].scatter(data[:, 0], data[:, 1], alpha=0.3, s=10, color='steelblue')
axes[0].set_xlabel("X1")
axes[0].set_ylabel("X2")
axes[0].set_title("2D Scatter Plot")
axes[0].set_aspect('equal')
axes[0].grid(True, alpha=0.3)
# 右: 共分散行列のヒートマップ
im = axes[1].imshow(cov_sample, cmap='coolwarm', vmin=-5, vmax=5)
for i in range(2):
for j in range(2):
axes[1].text(j, i, f'{cov_sample[i, j]:.3f}', ha='center', va='center', fontsize=14)
axes[1].set_xticks([0, 1])
axes[1].set_xticklabels(['X1', 'X2'])
axes[1].set_yticks([0, 1])
axes[1].set_yticklabels(['X1', 'X2'])
axes[1].set_title("Covariance Matrix")
plt.colorbar(im, ax=axes[1])
plt.tight_layout()
plt.show()
固有値分解との関係
共分散行列の固有値分解は、データの主要な変動方向を明らかにします。これは主成分分析(PCA)の数学的な基盤です。
$$ \bm{\Sigma} = \bm{V} \bm{\Lambda} \bm{V}^T $$
ここで、$\bm{V}$ は固有ベクトルを列に持つ直交行列、$\bm{\Lambda}$ は固有値を対角に持つ対角行列です。
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
# データ生成
mean = [2, 3]
cov_true = [[4, 2.5],
[2.5, 3]]
data = np.random.multivariate_normal(mean, cov_true, size=300)
# 共分散行列の固有値分解
cov_sample = np.cov(data.T)
eigenvalues, eigenvectors = np.linalg.eigh(cov_sample)
# 固有値の大きい順にソート
idx = np.argsort(eigenvalues)[::-1]
eigenvalues = eigenvalues[idx]
eigenvectors = eigenvectors[:, idx]
print(f"固有値: {eigenvalues}")
print(f"固有ベクトル:\n{eigenvectors}")
print(f"\n寄与率: {eigenvalues / eigenvalues.sum()}")
# 可視化: データと主成分方向
data_mean = data.mean(axis=0)
plt.figure(figsize=(8, 7))
plt.scatter(data[:, 0], data[:, 1], alpha=0.3, s=10, color='steelblue')
# 固有ベクトル(主成分方向)を矢印で描画
colors = ['red', 'green']
labels = ['PC1', 'PC2']
for i in range(2):
scale = np.sqrt(eigenvalues[i]) * 2
vec = eigenvectors[:, i] * scale
plt.annotate('', xy=data_mean + vec, xytext=data_mean,
arrowprops=dict(arrowstyle='->', color=colors[i], lw=3))
plt.text(data_mean[0] + vec[0] * 1.15, data_mean[1] + vec[1] * 1.15,
f'{labels[i]} (lambda={eigenvalues[i]:.2f})',
fontsize=12, color=colors[i], fontweight='bold')
plt.xlabel("X1")
plt.ylabel("X2")
plt.title("Eigenvectors of Covariance Matrix (Principal Components)")
plt.axis('equal')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
赤い矢印(PC1)がデータの最も大きな分散方向、緑の矢印(PC2)が直交する方向を示しています。矢印の長さは固有値の平方根に比例しており、各方向のデータの散らばりの大きさを表しています。
まとめ
本記事では、分散共分散行列について解説しました。
- 分散共分散行列は、多変量データの全変数間の共分散をまとめた対称行列
- 対角成分は各変数の分散、非対角成分は変数間の共分散
- 半正定値性を持ち、固有値は全て非負
- 固有値分解により、データの主要な変動方向(主成分)が得られる
- 主成分分析(PCA)の数学的基盤として、機械学習で広く利用されている