web-dev-qa-db-ja.com

matplotlibを使用したPCAの基本的な例

Matplotlib.mlab.PCAを使用して単純な主成分分析を実行しようとしていますが、クラスの属性を使用すると、問題の明確な解決策を得ることができません。次に例を示します。

2Dでダミーデータを取得し、PCAを開始します。

from matplotlib.mlab import PCA
import numpy as np

N     = 1000
xTrue = np.linspace(0,1000,N)
yTrue = 3*xTrue

xData = xTrue + np.random.normal(0, 100, N)
yData = yTrue + np.random.normal(0, 100, N)
xData = np.reshape(xData, (N, 1))
yData = np.reshape(yData, (N, 1))
data  = np.hstack((xData, yData))
test2PCA = PCA(data)

ここで、主成分を元の座標のベクトルとして取得し、それらを矢印としてデータにプロットしたいと思います。

そこにたどり着くための迅速でクリーンな方法は何ですか?

ありがとう、タイラックス

11
Tyrax

mlab.PCAクラスはあなたがやりたいことには適切ではないと思います。特に、PCAクラスは、固有ベクトルを見つける前にデータを再スケーリングします。

a = self.center(a)
U, s, Vh = np.linalg.svd(a, full_matrices=False)

centerメソッドはsigmaで除算します。

def center(self, x):
    'center the data using the mean and sigma from training set a'
    return (x - self.mu)/self.sigma

これにより、次のような固有ベクトルpca.Wtが生成されます。

[[-0.70710678 -0.70710678]
 [-0.70710678  0.70710678]]

それらは垂直ですが、元のデータの主軸に直接関連していません。これらは、マッサージされたデータに関する主軸です。

おそらく、(mlab.PCAクラスを使用せずに)必要なものを直接コーディングする方が簡単かもしれません。

import numpy as np
import matplotlib.pyplot as plt

N = 1000
xTrue = np.linspace(0, 1000, N)
yTrue = 3 * xTrue
xData = xTrue + np.random.normal(0, 100, N)
yData = yTrue + np.random.normal(0, 100, N)
xData = np.reshape(xData, (N, 1))
yData = np.reshape(yData, (N, 1))
data = np.hstack((xData, yData))

mu = data.mean(axis=0)
data = data - mu
# data = (data - mu)/data.std(axis=0)  # Uncommenting this reproduces mlab.PCA results
eigenvectors, eigenvalues, V = np.linalg.svd(data.T, full_matrices=False)
projected_data = np.dot(data, eigenvectors)
sigma = projected_data.std(axis=0).mean()
print(eigenvectors)

fig, ax = plt.subplots()
ax.scatter(xData, yData)
for axis in eigenvectors:
    start, end = mu, mu + sigma * axis
    ax.annotate(
        '', xy=end, xycoords='data',
        xytext=start, textcoords='data',
        arrowprops=dict(facecolor='red', width=2.0))
ax.set_aspect('equal')
plt.show()

enter image description here

27
unutbu