2013-08-18 3 views
7

Sto cercando di eseguire una semplice analisi delle componenti principali con matplotlib.mlab.PCA ma con gli attributi della classe non riesco a ottenere una soluzione pulita al mio problema. Ecco un esempio:Esempio di base per PCA con matplotlib

ottenere alcuni dati fittizi in 2D e iniziare 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) 

ora, voglio solo per ottenere i componenti principali come vettori nelle mie coordinate originali e tracciare come frecce sul mio dati.

Qual è un modo rapido e pulito per arrivarci?

Grazie, Tyrax

risposta

22

non credo che la classe mlab.PCA è appropriato per ciò che si vuole fare. In particolare, la classe PCA ridimensiona i dati prima di trovare gli autovettori:

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

Il metodo center divide per sigma:

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

Ciò si traduce in autovettori, pca.Wt, in questo modo:

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

Sono perpendicolari, ma non direttamente rilevanti per gli assi principali dei dati originali. Sono assi principali rispetto ai dati massaggiati.

Forse potrebbe essere più facile da codificare ciò che si vuole direttamente (senza l'uso della classe 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

grande, grazie. Questo è quello che stavo cercando. – Tyrax

+0

qual è il significato della costante 1.618? da dove viene ? – joaquin

+1

@joaquin: è approssimativamente il [rapporto aureo] (http://en.wikipedia.org/wiki/Golden_ratio). Puoi, ovviamente, scegliere qualsiasi costante che ti piace, ma [sembra spesso buona] (http://en.wikipedia.org/wiki/Golden_ratio#Painting). – unutbu