2013-08-18 3 views
7

Я пытаюсь сделать простой анализ основных компонентов с помощью matplotlib.mlab.PCA, но с атрибутами класса я не могу получить чистое решение моей проблемы. Вот пример:Базовый пример для PCA с matplotlib

Получить некоторые фиктивные данные в 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) 

Теперь, я просто хочу, чтобы получить основные компоненты как векторы в моих исходных координатах и ​​построить их в виде стрелок на мои данные.

Что такое быстрый и чистый способ добраться туда?

Спасибо, Tyrax

ответ

22

Я не думаю, что 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

+0

здорово, спасибо. Это то, что я искал. – Tyrax

+0

Что такое константа 1.618? откуда она взялась? – joaquin

+1

@joaquin: Его приблизительно [золотое соотношение] (http://en.wikipedia.org/wiki/Golden_ratio). Вы можете, конечно, выбрать любую константу, которая вам нравится, но она [часто выглядит хорошо] (http://en.wikipedia.org/wiki/Golden_ratio#Painting). – unutbu

Смежные вопросы