Pythonで標準化、無相関化、白色化を実装

www.amazon.co.jp
この本の第4章に出てくるグラフを実装しました。次の順番で説明していきます。

  • データの準備、確認
  • アヤメデータの標準化
  • アヤメデータの無相関化
  • アヤメデータの白色化

データの準備、確認

データ等の準備を行います。今回は教科書に合わせて、花弁の長さと幅だけに注目します。

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

iris = datasets.load_iris()
nagasa = iris.data[:,2]
haba = iris.data[:,3]

作成したnagasaとhabaベクトルには50標本ごとに、setosa、versicolor、virginicaが格納されていますので、それぞれ色を変えてプロットします。

plt.plot(nagasa[0:50],haba[0:50],'o',label='setosa')
plt.plot(nagasa[50:100],haba[50:100],'o',label='versicolor')
plt.plot(nagasa[100:150],haba[100:150],'o',label='virginica')
plt.xlim([0,8])
plt.ylim([-1,3])
plt.xlabel('length')
plt.ylabel('breadth')
plt.title('Before Standardization')
plt.legend(loc='lower right')
plt.show()

f:id:decompose:20160325234359p:plain

アヤメデータの標準化

これで図示できました。次に、標準化を行います。そのためには各変数を平均0、分散1にしていきます。

nagasa2 = nagasa - np.mean(nagasa)
haba2 = haba -np.mean(haba)
sd_nagasa = np.sqrt(sum(nagasa2*nagasa2)/np.size(nagasa2))
sd_haba = np.sqrt(sum(haba2*haba2)/np.size(haba2))

z_nagasa = nagasa2/sd_nagasa
z_haba = haba2/sd_haba

plt.plot(z_nagasa[0:50],z_haba[0:50],'o',label='setosa')
plt.plot(z_nagasa[50:100],z_haba[50:100],'o',label='versicolor')
plt.plot(z_nagasa[100:150],z_haba[100:150],'o',label='virginica')
plt.xlim([-1.7,2.0])
plt.ylim([-1.7,2.0])
plt.xlabel('length')
plt.ylabel('breadth')
plt.title('After Standardization')
plt.legend(loc='lower right')
plt.show()

f:id:decompose:20160325234416p:plain

アヤメデータの無相関化

まずは、分散共分散行列を計算し、Sigmaと置きます。次に、Sigma固有値固有ベクトルを求め、それぞれaとSと置きます。

Sigma = np.array([[sd_nagasa**2,covariance],[covariance,sd_haba**2]])
a,S = np.linalg.eig(Sigma) #eigenvalue,eigenvector

ここで、念のため固有ベクトルを並べたS(回転行列)の転置と逆行列が一致することを確認してみます。教科書の例題4.2ですね。

#Transpose of S equals inverse of S
np.linalg.inv(S) #inverse
S.transpose() #transpose

{y=S^T x}という線形変換を行うので、

X = iris.data[:,2:4]
Y = X.dot(S)

プロットしていきます。{Y}の一列目は長さ、{Y}の二列目は幅データであることに注意してください。

plt.plot(Y[0:50,0],Y[0:50,1],'o',label='setosa')
plt.plot(Y[50:100,0],Y[50:100,1],'o',label='versicolor')
plt.plot(Y[100:150,0],Y[100:150,1],'o',label='virginica')
plt.xlim([0.,7.5])
plt.ylim([-2,3.0])
plt.xlabel('length')
plt.ylabel('breadth')
plt.title('After Decorrelation')
plt.legend(loc='upper right')
plt.show()

f:id:decompose:20160325234447p:plain

アヤメデータの白色化

線形変換したベクトルの分散共分散行列である{\Lambda}を計算します。

Lambda = np.linalg.inv(S).dot(Sigma).dot(S)

白色化を行います。すべての特徴量の標準偏差を1に正規化し、かつ中心かを行う操作です。下記のLambda_invhalfは分散共分散行列から求めた固有値平方根を対角要素に並べた行列の逆行列です。

xmu =  X-np.mean(X,0)
Lambda_invhalf = np.linalg.inv(np.sqrt( np.diag (Lambda) ) * np.identity(2))
whiteX =xmu.dot(S).dot(Lambda_invhalf.transpose()) #教科書の式4.17

最後に、プロットしていきます。

plt.plot(whiteX[0:50,0],whiteX[0:50,1],'o',label='setosa')
plt.plot(whiteX[50:100,0],whiteX[50:100,1],'o',label='versicolor')
plt.plot(whiteX[100:150,0],whiteX[100:150,1],'o',label='virginica')
plt.xlim([-3.,3.])
plt.ylim([-3.,3.])
plt.xlabel('length')
plt.ylabel('breadth')
plt.title('After Whitening')
plt.legend(loc='lower left')
plt.show()

f:id:decompose:20160325234431p:plain