主成分分析(PCA)-理論とPythonで実装
はじめに
今回扱う主成分分析(Principal component analysis ; PCA)は、次元削減の有名な方法である。
pを次元数、nをデータ数とすると
はじめに理論を説明し、次にpythonで実装する。
主成分分析
平均
データ行列
Sの固有値分解は
この固有値、固有ベクトルを用いて次元を削減する。
どうやって削減するかというと、例えば2次元に削減するのであれば、
データを主成分方向に正射影した座標のことを主成分スコアと言う。
データ
である。
実際使う際は母平均はわからないので、標本主成分スコアを用いる。
寄与率を次のように定義する。
この割合を見ればどのくらいの情報が集約されているかわかる。
Pythonで実装
PCAのフルスクラッチ
import numpy as np
def pca(X, k):
# 1. データの中心化
mean = np.mean(X, axis=0)
X_centered = X - mean
# 2. 共分散行列を計算
S = np.cov(X_centered, rowvar=False)
# 3. 固有値と固有ベクトルを計算
lam, h = np.linalg.eigh(S)
# 4. 固有値を降順にソートし、対応する固有ベクトルも並べ替える
index = np.argsort(lam)[::-1]
sorted_lam = lam[index]
sorted_h = h[:, index]
# 5. 最も大きいk個の固有ベクトルを選ぶ
selected_h = sorted_h[:, :k]
# データを低次元空間に射影
X_pca = X_centered @ selected_h
return X_pca
実際、下記の方法で一瞬でPCAできてしまいます笑
sklearnによるPCA
from sklearn.decomposition import PCA
import numpy as np
X # データ
k #抽出する主成分の数
# PCAインスタンスを作成
pca = PCA(n_components=k)
# PCAモデルにデータをフィット
pca.fit(X)
# データを低次元に変換
X_pca = pca.transform(X)
print(X_pca)
Xとkに必要な値を入れれば終わりです。
おまけ
寄与率と累積寄与率のグラフを作成する。
pca =PCA()
pca.fit(x)
evr=pca.explained_variance_ratio_ #寄与率
cev=np.cumsum(evr) #累積寄与率
# 寄与率のプロット
plt.bar(range(1, len(evr) + 1), evr, alpha=0.5, align='center', label='寄与率')
# 累積寄与率のプロット
plt.step(range(1, len(cev) + 1), cev, where='mid', label='累積寄与率')
plt.xlabel("主成分")
plt.ylabel("寄与率")
plt.legend(loc='best')
plt.tight_layout()
plt.show()
例題
sklearnのwineのデータを2次元に射影して散布図を出力してみる。
まず必要なライブラリをインポートする。
!pip install japanize-matplotlib #日本語で出力するために必要
from sklearn.decomposition import PCA
import numpy as np
import pandas as pd
from sklearn import datasets
import matplotlib.pyplot as plt
%matplotlib inline
import japanize_matplotlib
#データ
wine_data = datasets.load_wine()
x = pd.DataFrame(wine_data.data, columns=wine_data.feature_names)
y = wine_data.target
# PCAインスタンスを作成
pca = PCA(n_components=2)
# PCAモデルにデータをフィットし、低次元に変換
wine_pca = pca.fit_transform(x)
plt.figure(figsize=(10, 7))
for color, i, target_name in zip(['red', 'green', 'blue'], [0, 1, 2], wine_data.target_names):
plt.scatter(wine_pca[y == i, 0], wine_pca[y == i, 1], color=color, label=target_name)
plt.xlabel('第1主成分')
plt.ylabel('第2主成分')
plt.legend()
plt.show()
2次元に射影したら流石に分類はできなそうですね。それでもクラス0はその他のクラス(1と2)と分類できそうですね。
でも寄与率見てみたら、第一主成分が99%なのでほぼほぼ情報は保ったまま次元削減できているみたいです。
まとめ
固有値と固有ベクトルを理解するのはかなり苦労するかもしれませんが、PCAをとりあえず実装してみて、情報を集約してるんだなって感じていただければ、理解が一歩進むかもしれないのでやってみてください。
Discussion