wake-up-neo.net

Hauptkomponentenanalyse (PCA) in Python

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.

55
khan

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!

48
EnricoGiampieri

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).

enter image description here

78
doug

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.

17
Mark

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

12
Calvin Cheng

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.

 PCA result plot

4
z80crew

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

Zusätzlich zu allen anderen Antworten gibt es hier einen Code zum Plotten der 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()

 enter image description here

1
seralou

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.

1
bendaf

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)
0
Edson