コンテンツにスキップ

第9回 PCA②:大規模データへの対応とバイプロット解釈

本日の到達目標

  • 固有値分解(EVD)・特異値分解(SVD)の計算量を説明できる
  • ランダム化SVDの原理と精度・速度のトレードオフを説明できる
  • バイプロットを使って主成分の解釈ができる
  • 発展:SVD の特異値と共分散行列の固有値の対応を導き、PCA が座標の回転には影響されないのに変数のスケール変更には影響される理由を説明できる

1. 計算量の問題

1.1 標準的な PCA の計算量

\(n\) 観測 × \(p\) 変数の行列 \(\mathbf{X}\) に対して標準的なPCAを実行するコスト:

ステップ 演算 計算量
共分散行列の計算 \(\mathbf{X}^T\mathbf{X}\) \(O(np^2)\)
固有値分解(または全SVD) \(p \times p\) 行列の分解 \(O(p^3)\)
主成分スコアの計算 \(\mathbf{X} \mathbf{V}\) \(O(npk)\)

問題となる場面: - \(n = 10^7\)(1000万件)、\(p = 100\)(時間窓特徴量100列)の場合 - 共分散行列の計算:\(O(10^7 \times 10^4) = O(10^{11})\) → 数分〜数十分 - 行列の格納だけで \(100 \times 100 \times 8 = 80,000\) バイト(問題ない) - \(n = 10^7\)、\(p = 10^4\) の場合(テキスト特徴等) - 共分散行列の格納:\(10^4 \times 10^4 \times 8 = 800\) MB → メモリ問題 - 固有値分解:\(O(p^3) = O(10^{12})\) → 非現実的

1.2 Truncated SVD

全固有値を求めず、上位 \(k\) 個だけを求める Truncated(打ち切り)SVD:

\[\mathbf{X} \approx \mathbf{U}_k \mathbf{\Sigma}_k \mathbf{V}_k^T\]
  • 計算量:\(O(npk)\)(\(k \ll p\) のとき大幅削減)
  • \(\mathbf{V}_k\):上位 \(k\) 個の右特異ベクトル → PCAの主成分方向に対応
  • \(\mathbf{\Sigma}_k\):上位 \(k\) 個の特異値 → \(\sigma_j^2/n \approx\) 固有値に対応
導出①:特異値と固有値の対応は近似ではなく等式である

本文で「\(\sigma_j^2/n \approx\) 固有値」と書きましたが、打ち切りをしなければこれは厳密な等式です。

\(\mathbf{X}\) の特異値分解を \(\mathbf{X} = \mathbf{U}\mathbf{\Sigma}\mathbf{V}^T\) とします(\(\mathbf{U}, \mathbf{V}\) は直交行列、\(\mathbf{\Sigma}\) は対角)。これを \(\mathbf{X}^T\mathbf{X}\) に代入します。

\[\mathbf{X}^T\mathbf{X} = (\mathbf{U}\mathbf{\Sigma}\mathbf{V}^T)^T(\mathbf{U}\mathbf{\Sigma}\mathbf{V}^T) = \mathbf{V}\mathbf{\Sigma}^T\mathbf{U}^T\mathbf{U}\mathbf{\Sigma}\mathbf{V}^T = \mathbf{V}\mathbf{\Sigma}^2\mathbf{V}^T\]

途中で \(\mathbf{U}^T\mathbf{U} = \mathbf{I}\) を使いました。最後の式は \(\mathbf{X}^T\mathbf{X}\) の固有値分解そのものです。読み取れることは2つあります。

  • \(\mathbf{X}^T\mathbf{X}\) の固有ベクトルは \(\mathbf{V}\) の列(右特異ベクトル)
  • \(\mathbf{X}^T\mathbf{X}\) の固有値は \(\sigma_j^2\)

共分散行列は \(\mathbf{S} = \mathbf{X}^T\mathbf{X}/n\) なので、その固有値は \(\sigma_j^2/n\) です。

なぜこれが実務で効くのか。 第8回の道筋では、まず \(\mathbf{S}\)(\(p \times p\))を作ってから固有値分解しました。この式は、\(\mathbf{S}\) を作らずに \(\mathbf{X}\) から直接主成分方向が得られることを示しています。\(p = 10^4\) のとき \(\mathbf{S}\) の格納だけで 800 MB かかりますが、SVD なら \(\mathbf{S}\) を作る必要がありません。近似になるのは上位 \(k\) 個で打ち切ったときだけで、対応関係そのものは厳密です。

使った数学:SVD の定義、直交行列の性質 \(\mathbf{U}^T\mathbf{U} = \mathbf{I}\)(線形代数)。


2. ランダム化SVD(Randomized SVD)

2.1 基本的なアイデア

直観:高次元行列でも「情報の多くは低次元の部分空間に集中している」

アルゴリズムの概略(Halko et al., 2011)

ステップ1: 乱数行列 Ω ∈ R^{p×(k+p)} を生成
ステップ2: Y = X Ω  → 列空間の近似的な基底を構成 (n × (k+p))
ステップ3: QR分解: Y = QR  → Q が近似列空間の正規直交基底
ステップ4: 小さな行列 B = Q^T X  → (k+p) × p
ステップ5: B の SVD を計算 → X の近似SVDを得る

計算量:\(O(npk)\) に抑えられる(\(n > p\) の場合)

2.2 精度と速度のトレードオフ

「オーバーサンプリングパラメータ」\(p\)(上記のアルゴリズムの \(k+p\) 部分):

設定 精度 速度
\(k\) のみ(\(p = 0\)) 低い 最速
\(k + 10\) 高い やや遅い(推奨)
\(k + 20\) さらに高い 遅い

電力反復(Power Iteration):\(\mathbf{X}^T\mathbf{X}\) を繰り返しかけることで精度を向上させる追加オプション

2.3 近似誤差の評価

フロベニウスノルムによる誤差:

\[\|\mathbf{X} - \mathbf{U}_k \mathbf{\Sigma}_k \mathbf{V}_k^T\|_F\]

k を大きくすると誤差は減少するが計算時間は増大する。

どこで打ち切るか: - 累積寄与率で決める(第8回の基準) - 実用では \(k = 50 \sim 100\) でほとんどのケースに対応


3. 標準化の重要性

3.1 スケールの影響

PCA は分散最大化を目指すため、スケールの大きい変数が優位になる。

例: - 売上(万円単位、分散 = 100万) - 気温(°C単位、分散 = 10)

標準化なしでは売上が第1主成分をほぼ一人で支配してしまう。

導出②:単位を変えると結果が変わるのは、分散が単位に依存する量だから

なぜスケールが結果を変えるのかを式で見ます。

変数 \(x_j\) の単位を変えて \(a\) 倍すると(例:円→万円なら \(a = 10^{-4}\))、共分散行列の該当成分は次のように変わります。

\[S_{jj} \to a^2 S_{jj}, \qquad S_{jk} \to a\,S_{jk} \quad (k \neq j)\]

対角成分は \(a^2\) 倍、非対角成分は \(a\) 倍と、変わり方が違うのが要点です。行列全体が定数倍されるのではないので、固有ベクトルの向きそのものが変わります。

第8回の導出③より、寄与率の分母は \(\text{tr}(\mathbf{S}) = \sum_j S_{jj}\) です。ある変数の \(S_{jj}\) が突出して大きければ、その変数だけで分母のほとんどを占めます。分散最大化は「いちばん散らばっている方向」を探す操作なので、単に目盛りが細かいだけの変数を最重要と判断してしまいます。

標準化すると全変数の分散が1になり、\(\text{tr}(\mathbf{S}) = p\)、\(\mathbf{S}\) は相関行列と一致します。相関行列ベースの PCA とは、この前処理をした共分散行列ベースの PCA のことです。

注意:標準化は万能の前処理ではありません。同じ単位で測った変数群で、分散の大小そのものに意味がある場合(例:同一センサーの複数チャネル)、標準化はその情報を消してしまいます。本文の表のとおり、単位が混在するときに使う道具です。

使った数学:一次変換に対する分散・共分散の変化則。

導出③:回転では分散の総量も固有値も変わらない

導出②と対比すると、PCA が何に影響され何に影響されないかがはっきりします。

座標系を直交行列 \(\mathbf{R}\) で回すと、共分散行列は \(\mathbf{S} \to \mathbf{R}^T\mathbf{S}\mathbf{R}\) と変わります。ここでトレースの巡回性 \(\text{tr}(\mathbf{AB}) = \text{tr}(\mathbf{BA})\) と \(\mathbf{R}\mathbf{R}^T = \mathbf{I}\) を使うと、

\[\text{tr}(\mathbf{R}^T\mathbf{S}\mathbf{R}) = \text{tr}(\mathbf{S}\mathbf{R}\mathbf{R}^T) = \text{tr}(\mathbf{S})\]

分散の総量は変わりません。固有値も変わりません(固有ベクトルが一緒に回るだけです)。

数値で確かめる:\(\mathbf{S} = \begin{pmatrix} 4.0 & 1.2 \\ 1.2 & 1.0 \end{pmatrix}\) を 0.7 ラジアン回転させると、対角和は \(5.000000\) のまま、固有値も \((4.420937,\ 0.579063)\) のままでした。

2つを並べると:PCA は座標軸の取り方(回転)には影響されないが、変数ごとの目盛りの取り替え(スケール変更)には影響される。前者は分散の総量を保つ変換、後者は保たない変換だからです。「標準化が必要か」という問いは、この区別の上に立っています。

使った数学:トレースの巡回性、直交行列の性質(線形代数)。

3.2 相関行列 vs 共分散行列

行列 前処理 推奨場面
共分散行列 スケール調整なし 変数が同一単位で意味がある場合
相関行列 各列を標準化(平均0・分散1) 変数の単位が異なる場合(通常こちら)

時間窓特徴量の場合:単位が混在(金額・回数・温度等)→ 標準化推奨


4. バイプロット(Biplot)

4.1 バイプロットとは

主成分スコア(観測点)とローディング(元変数の矢印)を同一プロット上に描く可視化手法。

PC2 ↑
 0.4|   頻度30日↗        ○ グループA
    |       ↗                  ○ ○
 0.0|──────────→ PC1  ○   ○ ○
    |  MA7日→    ○        ○
-0.4|  MA30日→
    |

4.2 読み方

観測点(点)の解釈 - 近くにある点 → 似た特性を持つ - 離れた点 → 異なる特性

矢印(ローディング)の解釈 - 矢印の長さ → その変数の第1・第2主成分への寄与の大きさ - 矢印の方向 → その変数が強く関係する主成分の方向 - 同じ方向の矢印 → 正の相関 - 反対方向の矢印 → 負の相関 - 直交する矢印 → 無相関

4.3 解釈の例(時間窓特徴量)

第1主成分(PC1)と第2主成分(PC2)のバイプロットで:
- MA7日, MA30日, 直近値 → PC1 方向に揃う
  → PC1 ≈「売上水準の高さ」
- 頻度30日, 頻度7日 → PC2 方向に揃う
  → PC2 ≈「来店頻度の高さ」

5. 近似SVDと精密SVDの比較実験設計

5.1 実験の枠組み

同一データ X (スナップショット固定: 第3回)
   ├→ 精密SVD (全成分): 基準
   ├→ ランダム化SVD (k=10, p=0): 精度低・速い
   ├→ ランダム化SVD (k=10, p=10): 精度高・やや遅い
   └→ ランダム化SVD (k=50, p=10): 精度高・比較的速い

評価指標: - 上位10成分の固有値の差(精密との比較) - 累積寄与率の差 - 実行時間

5.2 DAGによる比較管理

features.parquet(固定スナップショット)
   ├→ 標準化
   └→ 各手法の実行(DAGで並列化可能)
         ↓
   固有値・寄与率の比較表
         ↓
   バイプロットの比較可視化

6. 基盤リンクの整理

基盤概念 本回での役割 具体的な使い方
列指向 部分行列抽出・サンプリングの効率化 大規模時に必要な列だけ読んでランダム化SVD
整合性 比較実験で同条件を維持 全手法が同一スナップショットを使う
DAG 近似→評価→解釈を一連の処理として管理 各手法の実行をDAGで並列化
近似 ランダム化SVDで計算をスケールさせる \(O(p^3) → O(npk)\) への計算量削減

7. 本日のまとめ

  1. 標準的なSVD/EVDは \(O(p^3)\) →大規模・高次元では非現実的
  2. ランダム化SVD:\(O(npk)\) で上位 \(k\) 成分を近似取得。精度はオーバーサンプリングパラメータで制御
  3. 変数の単位が異なる場合は相関行列ベースのPCA(標準化後に実行)
  4. バイプロット:観測点とローディング矢印を同一図で可視化し、主成分の意味を解釈する

次回予告

第10回では k-means①:クラスタ内分散最小化の目的関数を理解し、PCA出力を入力としてデータを類型化する方法を学ぶ。


事後課題

以下を調べ、A4半枚程度でまとめること:

  1. scikit-learn の TruncatedSVD と PCA クラスの違いを調べ、どちらをどの場面で使うべきか説明してください。
  2. ランダム化SVDは「乱数を使う」のに、なぜ毎回ほぼ同じ結果が得られるのか直観的に説明してください。