PCA

2.6.1

PCA

最終更新 2020-01-29 読了時間 2 分
まとめ
  • PCA は分散が最大となる直交軸を順に求め、情報損失を抑えながら次元を圧縮する。
  • 寄与率を用いて、必要な主成分数を定量的に選択できる。
  • スケール差の影響が大きいため、標準化の有無を必ず確認する。

直感 #

PCAは、データの散らばりが最も大きい向きを新しい座標軸として取り直す処理です。情報量の大きい方向を優先して残すことで、次元を減らしても主要な構造を維持できます。

詳細な解説 #


1. 直感:データの「一番ばらつく方向」を探す #

  • 高次元データを扱うと「特徴量が多すぎて扱いづらい」ことが多い。
  • PCAは、データが最も広がっている方向(= 分散が最大の方向)を探して、その方向を新しい軸(主成分)として使う。
  • こうすることで「情報をなるべく失わずに次元を減らす」ことができる。

2. 数式でみる PCA #

データ行列 \(X \in \mathbb{R}^{n \times d}\) を平均 0 に正規化したとする。

  1. 共分散行列を計算: $$ \Sigma = \frac{1}{n} X^\top X $$

  2. 固有値分解: $$ \Sigma v_j = \lambda_j v_j $$

    • \(v_j\):主成分ベクトル(固有ベクトル)
    • \(\lambda_j\):対応する分散(固有値)
  3. 主成分得点(低次元データ): $$ Z = X V_k $$ ここで \(V_k\) は固有値の大きい順に \(k\) 個のベクトルを並べた行列。


3. 実験用のデータ #

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

X, y = make_blobs(n_samples=600, n_features=3, random_state=117117)

fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(projection="3d")
ax.scatter(X[:, 0], X[:, 1], X[:, 2], marker="o", c=y)
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.set_zlabel("$x_3$")

実験用のデータの図


4. PCAで二次元に次元削減する #

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

pca = PCA(n_components=2, whiten=True)
X_pca = pca.fit_transform(StandardScaler().fit_transform(X))

plt.figure(figsize=(8, 8))
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("PCAによる2次元化")
plt.show()

PCAで二次元に次元削減するの図


5. 正規化の効果 #

PCAは「分散の大きさ」に敏感なので、スケールの違う特徴量を持つ場合は正規化(標準化)が必須です。

例1: 正規化なし vs 正規化あり #

from sklearn.preprocessing import StandardScaler

# 特徴量のスケールがバラバラなデータ
X, y = make_blobs(
    n_samples=200, n_features=3, random_state=11711, centers=3, cluster_std=2.0
)
X[:, 1] = X[:, 1] * 1000
X[:, 2] = X[:, 2] * 0.01

X_ss = StandardScaler().fit_transform(X)

# PCA実行
pca = PCA(n_components=2).fit(X)
X_pca = pca.transform(X)

pca_ss = PCA(n_components=2).fit(X_ss)
X_pca_ss = pca_ss.transform(X_ss)

plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.title("正規化なし")
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, marker="x", alpha=0.6)
plt.subplot(122)
plt.title("正規化あり")
plt.scatter(X_pca_ss[:, 0], X_pca_ss[:, 1], c=y, marker="x", alpha=0.6)
plt.show()

例1: 正規化なし vs 正規化ありの図


6. 実務での応用 #

  • 可視化:高次元データを2次元に落としてプロット
  • ノイズ除去:情報量の少ない主成分を削除することで精度向上
  • 特徴量圧縮:学習時間の短縮や過学習防止
  • 前処理:クラスタリングや回帰・分類の前段で使うと有効

発展:PCAのさらに深い話題 #

1. 寄与率と累積寄与率 #

  • 各主成分の寄与率は、固有値の割合で計算される: $$ \text{寄与率} = \frac{\lambda_j}{\sum_i \lambda_i} $$
  • 累積寄与率が 80〜90% を超える次元数を選ぶのが一般的。

2. SVDによる計算 #

実装上は「特異値分解 (SVD)」で計算されることが多い。
\(X = U \Sigma V^\top\) の形に分解し、\(V\) の列ベクトルが主成分に対応する。

3. カーネルPCA #

非線形な構造をとらえるために「カーネル法」を使う拡張版。
クラスタが曲線状に広がる場合などに有効。