numpyで無相関化・白色化する

最近通っているディープラーニングの講習会にて、BatchNormalizationの文脈でデータの白色化なるものについて触れましたので、「はじめてのパターン認識」を読みながらnumpyで実装してみます。

はじめてのパターン認識

はじめてのパターン認識

白色化とは

白色化 (whitening) \vec{x} (d次元) の各特徴量を無相関化し、かつ、平均0・標準偏差1にすることです。

無相関化

最初に行う無相関化では、各特徴量の相関係数が0になるように線形変換します。

サンプル数n・次元数dの入力行列  {\bf X} (n行×d列) から、平均ベクトル  \vec{\mu} (1×d) と共分散行列  {\bf \Sigma} (d×d) を計算します。

  •  {\bf \Sigma} の各要素  \sigma_{i,j} は、i=jなら分散、i≠jなら共分散です

$$ \vec{\mu} = (\mu_1, ..., \mu_d) = (E[\vec{X_1}], ..., E[\vec{X_d}]) $$

$$ {\bf \Sigma} = E[(\vec{x} - \vec{\mu})(\vec{x} - \vec{\mu})^T] $$

共分散行列を固有値  \lambda_i ・固有ベクトル  \vec{s}_i に分解し、固有ベクトルを列ベクトルとして結合した行列  {\bf S} を得ます。

  •  {\bf \Sigma} \vec{s_i} = \lambda_i \vec{s_i} の関係となります
  • 固有値分解はnumpy.linalg.eigで計算できます

あとは  {\bf S} を使って変換後の  \vec{x'} を計算します。

  •  {\bf S} は元の座標系から小昨夜靴方向へ回転させる回転行列となってます
  • 固有値は対応する固有ベクトル方向の分散となります

$$ \vec{x'} = {\bf S}^T \vec{x} $$

これで各特徴量間の相関係数は0となります。

白色化

無相関化後に、平均0・標準偏差1にします。

固有値  \lambda_i を対角化した行列  {\bf \Lambda} を定義し、以下の計算を行います。

$$ \vec{x'} = {\bf \Lambda}^{-\frac{1}{2}} {\bf S}^{T} (\vec{x} - \vec{\mu}) $$

numpyでの実装

irisデータセットを使った白色化の実装は以下です。

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

d = 2
n = 50

# データセットのロード
iris = load_iris()

# setosaの萼片の長さ・幅のみを使う
X = iris.data[iris.target == 0][:, :d].T  # (2, 50)
plt.scatter(X[0], X[1])  # 元の散布図

# 平均ベクトル
mu = np.mean(X, axis=1).reshape((d, 1))  # (2, 1)

# 共分散行列
Sigma = np.dot((X - mu), (X - mu).T) / n  # (2, 2)

# 無相関化
lam, S = np.linalg.eig(Sigma)  # 固有値・固有ベクトルに分解

X_dash = np.dot(S.T, X)  # (50, 2)
plt.scatter(X_dash[0], X_dash[1])  # 無相関化後の散布図

# 白色化
Lambda = np.diag(lam)  # 固有値の対角化

X_dash = np.dot(
    np.linalg.inv(np.sqrt(Lambda)),
    np.dot(S.T, (X - mu))
)
plt.scatter(X_dash[0], X_dash[1])  # 白色化後の散布図

元の2変数 (  x_1, x_2 ) は正の相関関係にあります。萼片の長さ・幅ですので、当然一方が大きくなれば他方も大きくなる関係になります。

f:id:ohke:20190615155344p:plain

無相関化後の散布図では、2軸間 (  x'_1, x'_2 ) では相関が無くなります。

f:id:ohke:20190615155633p:plain

白色化後はさらに平均0・標準偏差1にスケールされていることがわかります。

f:id:ohke:20190615160211p:plain