Ich habe ein Array (26424 x 144) und möchte PCA darüber mit Python ausführen. Es gibt jedoch keinen bestimmten Ort im Internet, der erklärt, wie diese Aufgabe gelöst werden kann (Es gibt einige Websites, die PCA nur nach ihren eigenen Vorstellungen durchführen - es gibt keine verallgemeinernde Methode, die ich finden kann). Jeder, der Hilfe hat, wird großartige Arbeit leisten.
Sie finden eine PCA-Funktion im matplotlib-Modul:
import numpy as np
from matplotlib.mlab import PCA
data = np.array(np.random.randint(10,size=(10,3)))
results = PCA(data)
die Ergebnisse speichern die verschiedenen Parameter der PCA . Sie stammen vom mlab-Teil von Matplotlib, der Kompatibilitätsebene mit der MATLAB-Syntax
EDIT: Auf dem Blog nextgenetics Ich fand eine wundervolle Demonstration, wie man eine PCA mit dem matplotlib mlab-Modul ausführt und anzeigt, viel Spaß beim Durchstöbern des Blogs!
Ich habe meine Antwort gepostet, obwohl bereits eine andere Antwort akzeptiert wurde. Die akzeptierte Antwort basiert auf einer veralteten Funktion ; Darüber hinaus basiert diese veraltete Funktion auf Singular Value Decomposition (SVD), die (obwohl durchaus gültig) die wesentlich speicher- und prozessorintensivere der beiden allgemeinen Verfahren zur Berechnung der PCA ist. Dies ist hier insbesondere wegen der Größe des Datenfeldes im OP relevant. Bei Verwendung der Kovarianz-basierten PCA ist das im Berechnungsfluss verwendete Array nur 144 x 144 und nicht 26424 x 144 (die Abmessungen des ursprünglichen Datenarrays).
Hier ist eine einfach funktionierende Implementierung von PCA unter Verwendung des Moduls linalg von SciPy. Da diese Implementierung zuerst die Kovarianzmatrix berechnet und dann alle nachfolgenden Berechnungen für dieses Array ausführt, benötigt sie weitaus weniger Speicher als SVD-basierte PCA.
(Das Linalg-Modul in NumPy kann neben der Importanweisung auch ohne Änderung des nachstehenden Codes verwendet werden. Dies wäre von Numpy Importlinalg als LA.)
Die zwei wichtigsten Schritte dieser PCA-Implementierung sind:
berechnen der Kovarianzmatrix; und
die eivenvectors & Eigenwerte dieser cov Matrix nehmen
In der folgenden Funktion bezieht sich der Parameter dims_rescaled_data auf die gewünschte Anzahl von Dimensionen in der Datenmatrix rescaled; Dieser Parameter hat einen Standardwert von nur zwei Dimensionen, aber der folgende Code ist nicht auf zwei beschränkt, er könnte jedoch any sein, der kleiner ist als die Spaltennummer des ursprünglichen Datenarrays.
def PCA(data, dims_rescaled_data=2):
"""
returns: data transformed in 2 dims/columns + regenerated original data
pass in: data as 2D NumPy array
"""
import numpy as NP
from scipy import linalg as LA
m, n = data.shape
# mean center the data
data -= data.mean(axis=0)
# calculate the covariance matrix
R = NP.cov(data, rowvar=False)
# calculate eigenvectors & eigenvalues of the covariance matrix
# use 'eigh' rather than 'eig' since R is symmetric,
# the performance gain is substantial
evals, evecs = LA.eigh(R)
# sort eigenvalue in decreasing order
idx = NP.argsort(evals)[::-1]
evecs = evecs[:,idx]
# sort eigenvectors according to same index
evals = evals[idx]
# select the first n eigenvectors (n is desired dimension
# of rescaled data array, or dims_rescaled_data)
evecs = evecs[:, :dims_rescaled_data]
# carry out the transformation on the data using eigenvectors
# and return the re-scaled data, eigenvalues, and eigenvectors
return NP.dot(evecs.T, data.T).T, evals, evecs
def test_PCA(data, dims_rescaled_data=2):
'''
test by attempting to recover original data array from
the eigenvectors of its covariance matrix & comparing that
'recovered' array with the original data
'''
_ , _ , eigenvectors = PCA(data, dim_rescaled_data=2)
data_recovered = NP.dot(eigenvectors, m).T
data_recovered += data_recovered.mean(axis=0)
assert NP.allclose(data, data_recovered)
def plot_pca(data):
from matplotlib import pyplot as MPL
clr1 = '#2026B2'
fig = MPL.figure()
ax1 = fig.add_subplot(111)
data_resc, data_orig = PCA(data)
ax1.plot(data_resc[:, 0], data_resc[:, 1], '.', mfc=clr1, mec=clr1)
MPL.show()
>>> # iris, probably the most widely used reference data set in ML
>>> df = "~/iris.csv"
>>> data = NP.loadtxt(df, delimiter=',')
>>> # remove class labels
>>> data = data[:,:-1]
>>> plot_pca(data)
Die folgende Abbildung zeigt diese PCA-Funktion visuell auf den Iris-Daten. Wie Sie sehen, trennt eine 2D-Transformation die Klasse I sauber von Klasse II und Klasse III (nicht jedoch Klasse II von Klasse III, die tatsächlich eine andere Dimension erfordert).
Eine weitere Python-PCA, die numpy verwendet. Die gleiche Idee wie bei @doug, aber die lief nicht.
from numpy import array, dot, mean, std, empty, argsort
from numpy.linalg import eigh, solve
from numpy.random import randn
from matplotlib.pyplot import subplots, show
def cov(data):
"""
Covariance matrix
note: specifically for mean-centered data
note: numpy's `cov` uses N-1 as normalization
"""
return dot(X.T, X) / X.shape[0]
# N = data.shape[1]
# C = empty((N, N))
# for j in range(N):
# C[j, j] = mean(data[:, j] * data[:, j])
# for k in range(j + 1, N):
# C[j, k] = C[k, j] = mean(data[:, j] * data[:, k])
# return C
def pca(data, pc_count = None):
"""
Principal component analysis using eigenvalues
note: this mean-centers and auto-scales the data (in-place)
"""
data -= mean(data, 0)
data /= std(data, 0)
C = cov(data)
E, V = eigh(C)
key = argsort(E)[::-1][:pc_count]
E, V = E[key], V[:, key]
U = dot(data, V) # used to be dot(V.T, data.T).T
return U, E, V
""" test data """
data = array([randn(8) for k in range(150)])
data[:50, 2:4] += 5
data[50:, 2:5] += 5
""" visualize """
trans = pca(data, 3)[0]
fig, (ax1, ax2) = subplots(1, 2)
ax1.scatter(data[:50, 0], data[:50, 1], c = 'r')
ax1.scatter(data[50:, 0], data[50:, 1], c = 'b')
ax2.scatter(trans[:50, 0], trans[:50, 1], c = 'r')
ax2.scatter(trans[50:, 0], trans[50:, 1], c = 'b')
show()
Was das gleiche wie das viel kürzere ergibt
from sklearn.decomposition import PCA
def pca2(data, pc_count = None):
return PCA(n_components = 4).fit_transform(data)
Soweit ich es verstehe, ist die Verwendung von Eigenwerten (erster Weg) für hochdimensionale Daten und weniger Samples besser, während die Zerlegung des Singularwerts besser ist, wenn Sie mehr Samples als Dimensionen haben.
Dies ist ein Job für numpy
.
Und hier ist ein Tutorial, das zeigt, wie die Analyse von Hauptkomponenten mit den in numpy
integrierten Modulen wie mean,cov,double,cumsum,dot,linalg,array,rank
durchgeführt werden kann.
http://glowingpython.blogspot.sg/2011/07/principal-component-analysis-with-numpy.html
Beachten Sie, dass scipy
auch hier eine lange Erklärung hat - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/utils/extmath.py#L105
die Bibliothek scikit-learn
enthält weitere Codebeispiele - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/utils/extmath.py#L105
UPDATE:matplotlib.mlab.PCA
ist seit Version 2.2 (2018-03-06) in der Tat veraltet .
Die Bibliothek matplotlib.mlab.PCA
(in diese Antwort verwendet) ist not veraltet. Für alle Leute, die hier über Google ankommen, werde ich ein komplettes Arbeitsbeispiel mit Python 2.7 testen.
Verwenden Sie den folgenden Code mit Bedacht, da er jetzt eine veraltete Bibliothek verwendet!
from matplotlib.mlab import PCA
import numpy
data = numpy.array( [[3,2,5], [-2,1,6], [-1,0,4], [4,3,4], [10,-5,-6]] )
pca = PCA(data)
In `pca.Y 'ist jetzt die ursprüngliche Datenmatrix in Bezug auf die Basisvektoren der Hauptkomponenten. Weitere Details zum PCA-Objekt finden Sie hier .
>>> pca.Y
array([[ 0.67629162, -0.49384752, 0.14489202],
[ 1.26314784, 0.60164795, 0.02858026],
[ 0.64937611, 0.69057287, -0.06833576],
[ 0.60697227, -0.90088738, -0.11194732],
[-3.19578784, 0.10251408, 0.00681079]])
Sie können matplotlib.pyplot
verwenden, um diese Daten zu zeichnen, um sich selbst davon zu überzeugen, dass die PCA "gute" Ergebnisse liefert. Die names
-Liste dient nur zur Annotation unserer fünf Vektoren.
import matplotlib.pyplot
names = [ "A", "B", "C", "D", "E" ]
matplotlib.pyplot.scatter(pca.Y[:,0], pca.Y[:,1])
for label, x, y in Zip(names, pca.Y[:,0], pca.Y[:,1]):
matplotlib.pyplot.annotate( label, xy=(x, y), xytext=(-2, 2), textcoords='offset points', ha='right', va='bottom' )
matplotlib.pyplot.show()
Wenn Sie unsere ursprünglichen Vektoren betrachten, werden wir sehen, dass Daten [0] ("A") und Daten [3] ("D") ziemlich ähnlich sind wie Daten [1] ("B") und Daten [2] ("). C "). Dies spiegelt sich im 2D-Diagramm unserer PCA-transformierten Daten wider.
Hier gibt es Möglichkeiten zum Lernen von Scikit. Bei beiden Methoden wurde StandardScaler verwendet, da PCA durch Skalierung erfolgt
Methode 1: Lassen Sie scikit-learn die Anzahl der Hauptkomponenten minimum so wählen, dass mindestens x% (im Beispiel unten 90%) der Varianz erhalten bleibt.
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
iris = load_iris()
# mean-centers and auto-scales the data
standardizedData = StandardScaler().fit_transform(iris.data)
pca = PCA(.90)
principalComponents = pca.fit_transform(X = standardizedData)
# To get how many principal components was chosen
print(pca.n_components_)
Methode 2: Wählen Sie die Anzahl der Hauptkomponenten (in diesem Fall wurde 2 ausgewählt)
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
iris = load_iris()
standardizedData = StandardScaler().fit_transform(iris.data)
pca = PCA(n_components=2)
principalComponents = pca.fit_transform(X = standardizedData)
# to get how much variance was retained
print(pca.explained_variance_ratio_.sum())
Quelle: https://towardsdatascience.com/pca-using-python-scikit-learn-e653f8989e60
biplot
mit sklearn
und matplotlib
.import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
import pandas as pd
from sklearn.preprocessing import StandardScaler
iris = datasets.load_iris()
X = iris.data
y = iris.target
#In general a good idea is to scale the data
scaler = StandardScaler()
scaler.fit(X)
X=scaler.transform(X)
pca = PCA()
x_new = pca.fit_transform(X)
def myplot(score,coeff,labels=None):
xs = score[:,0]
ys = score[:,1]
n = coeff.shape[0]
scalex = 1.0/(xs.max() - xs.min())
scaley = 1.0/(ys.max() - ys.min())
plt.scatter(xs * scalex,ys * scaley, c = y)
for i in range(n):
plt.arrow(0, 0, coeff[i,0], coeff[i,1],color = 'r',alpha = 0.5)
if labels is None:
plt.text(coeff[i,0]* 1.15, coeff[i,1] * 1.15, "Var"+str(i+1), color = 'g', ha = 'center', va = 'center')
else:
plt.text(coeff[i,0]* 1.15, coeff[i,1] * 1.15, labels[i], color = 'g', ha = 'center', va = 'center')
plt.xlim(-1,1)
plt.ylim(-1,1)
plt.xlabel("PC{}".format(1))
plt.ylabel("PC{}".format(2))
plt.grid()
#Call the function. Use only the 2 PCs.
myplot(x_new[:,0:2],np.transpose(pca.components_[0:2, :]))
plt.show()
Ich habe ein kleines Skript zum Vergleich der verschiedenen PCAs erstellt, die hier als Antwort auftauchen:
import numpy as np
from scipy.linalg import svd
shape = (26424, 144)
repeat = 20
pca_components = 2
data = np.array(np.random.randint(255, size=shape)).astype('float64')
# data normalization
# data.dot(data.T)
# (U, s, Va) = svd(data, full_matrices=False)
# data = data / s[0]
from fbpca import diffsnorm
from timeit import default_timer as timer
from scipy.linalg import svd
start = timer()
for i in range(repeat):
(U, s, Va) = svd(data, full_matrices=False)
time = timer() - start
err = diffsnorm(data, U, s, Va)
print('svd time: %.3fms, error: %E' % (time*1000/repeat, err))
from matplotlib.mlab import PCA
start = timer()
_pca = PCA(data)
for i in range(repeat):
U = _pca.project(data)
time = timer() - start
err = diffsnorm(data, U, _pca.fracs, _pca.Wt)
print('matplotlib PCA time: %.3fms, error: %E' % (time*1000/repeat, err))
from fbpca import pca
start = timer()
for i in range(repeat):
(U, s, Va) = pca(data, pca_components, True)
time = timer() - start
err = diffsnorm(data, U, s, Va)
print('facebook pca time: %.3fms, error: %E' % (time*1000/repeat, err))
from sklearn.decomposition import PCA
start = timer()
_pca = PCA(n_components = pca_components)
_pca.fit(data)
for i in range(repeat):
U = _pca.transform(data)
time = timer() - start
err = diffsnorm(data, U, _pca.explained_variance_, _pca.components_)
print('sklearn PCA time: %.3fms, error: %E' % (time*1000/repeat, err))
start = timer()
for i in range(repeat):
(U, s, Va) = pca_mark(data, pca_components)
time = timer() - start
err = diffsnorm(data, U, s, Va.T)
print('pca by Mark time: %.3fms, error: %E' % (time*1000/repeat, err))
start = timer()
for i in range(repeat):
(U, s, Va) = pca_doug(data, pca_components)
time = timer() - start
err = diffsnorm(data, U, s[:pca_components], Va.T)
print('pca by doug time: %.3fms, error: %E' % (time*1000/repeat, err))
pca_mark ist die pca in Marks Antwort .
pca_doug ist der pca in dougs antwort .
Hier ist eine Beispielausgabe (das Ergebnis hängt jedoch sehr stark von der Datengröße und den pca_components ab. Ich würde daher empfehlen, einen eigenen Test mit Ihren eigenen Daten durchzuführen. Außerdem ist Facebooks pca für normalisierte Daten optimiert, sodass es schneller und schneller wird genauer in diesem Fall):
svd time: 3212.228ms, error: 1.907320E-10
matplotlib PCA time: 879.210ms, error: 2.478853E+05
facebook pca time: 485.483ms, error: 1.260335E+04
sklearn PCA time: 169.832ms, error: 7.469847E+07
pca by Mark time: 293.758ms, error: 1.713129E+02
pca by doug time: 300.326ms, error: 1.707492E+02
EDIT:
Die Funktion diffsnorm aus fbpca berechnet den spektralen Normfehler einer Schur-Zerlegung.
Damit def plot_pca(data):
funktionieren kann, müssen die Zeilen ersetzt werden
data_resc, data_orig = PCA(data)
ax1.plot(data_resc[:, 0], data_resc[:, 1], '.', mfc=clr1, mec=clr1)
mit Zeilen
newData, data_resc, data_orig = PCA(data)
ax1.plot(newData[:, 0], newData[:, 1], '.', mfc=clr1, mec=clr1)