J'ai un tableau (26424 x 144) et je veux effectuer PCA dessus en utilisant Python. Cependant, il n'y a pas d'endroit particulier sur le Web qui explique comment accomplir cette tâche (certains sites ne font que PCA selon leurs propres critères - il n'y a pas de moyen généralisé de le faire que je puisse trouver). N'importe qui avec n'importe quelle sorte d'aide fera de grands efforts.
Vous pouvez trouver une fonction PCA dans le module matplotlib:
import numpy as np
from matplotlib.mlab import PCA
data = np.array(np.random.randint(10,size=(10,3)))
results = PCA(data)
les résultats stockeront les différents paramètres de la PCA . Il provient de la partie mlab de matplotlib, qui est la couche de compatibilité avec la syntaxe MATLAB.
EDIT: Sur le blog nextgenetics J'ai trouvé une démonstration merveilleuse de la performance et de l'affichage d'une PCA avec le module matplotlib mlab.
J'ai posté ma réponse même si une autre réponse a déjà été acceptée; la réponse acceptée s'appuie sur un fonction déconseillée ; En outre, cette fonction déconseillée est basée sur décomposition en valeurs singulières (SVD), qui (bien que parfaitement valide) est la beaucoup plus gourmande en mémoire et en processeur des deux techniques générales de calcul de la PCA. Ceci est particulièrement pertinent ici en raison de la taille du tableau de données dans l'OP. En utilisant la PCA basée sur la covariance, le tableau utilisé dans le flux de calcul est simplement 144 x 144, plutôt que 26424 x 144 (les dimensions du tableau de données d'origine).
Voici une simple implémentation de travail de PCA utilisant le module linalg de SciPy. Étant donné que cette implémentation calcule d'abord la matrice de covariance, puis effectue tous les calculs ultérieurs sur ce tableau, elle utilise beaucoup moins de mémoire que la PCA basée sur SVD.
(Le module linalg dans NumPy peut également être utilisé sans modification du code ci-dessous, à l'exception de l'instruction import, qui serait de numpy import linalg sous LA.)
Les deux étapes clés de cette mise en œuvre de la PCA sont les suivantes:
calculer la matrice de covariance; et
prendre le eivenvectors & valeurs propres de cette matrice cov
Dans la fonction ci-dessous, le paramètre dims_rescaled_data fait référence au nombre souhaité de dimensions dans la matrice de données rescaled; ce paramètre a une valeur par défaut de seulement deux dimensions, mais le code ci-dessous n'est pas limité à deux, mais il pourrait être tout valeur inférieure au numéro de colonne du tableau de données d'origine.
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)
Le graphique ci-dessous est une représentation visuelle de cette fonction PCA sur les données de l'iris. Comme vous pouvez le constater, une transformation 2D sépare nettement les classes I des classes II et III (mais pas la classe II de la classe III, qui nécessite en fait une autre dimension).
Un autre PCA Python utilisant numpy. La même idée que @doug mais celle-là n'a pas fonctionné.
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()
Ce qui donne la même chose que le beaucoup plus court
from sklearn.decomposition import PCA
def pca2(data, pc_count = None):
return PCA(n_components = 4).fit_transform(data)
Si je comprends bien, utiliser des valeurs propres (première méthode) est préférable pour les données de grande dimension et moins d'échantillons, alors que la décomposition en valeurs singulières est préférable si vous avez plus d'échantillons que de dimensions.
Ceci est un travail pour numpy
.
Et voici un tutoriel qui montre comment l’analyse en composantes pincipal peut être réalisée à l’aide des modules intégrés de numpy
comme mean,cov,double,cumsum,dot,linalg,array,rank
.
http://glowingpython.blogspot.sg/2011/07/principal-component-analysis-with-numpy.html
Notez que scipy
a également une longue explication ici - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/extm .py # L105
avec la bibliothèque scikit-learn
ayant plus d'exemples de code - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/utils/ext py # L105
UPDATE:matplotlib.mlab.PCA
est depuis la version 2.2 (2018-03-06) en effet obsolète .
La bibliothèque matplotlib.mlab.PCA
(utilisée dans cette réponse ) est not obsolète. Donc, pour tous les gens qui arrivent ici via Google, je posterai un exemple de travail complet testé avec Python 2.7.
Utilisez le code suivant avec précaution car il utilise une bibliothèque désormais obsolète!
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)
Maintenant, dans «pca.Y» se trouve la matrice de données originale en termes de vecteurs de base de composantes principales. Vous trouverez plus de détails sur l’objet PCA ici .
>>> 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]])
Vous pouvez utiliser matplotlib.pyplot
pour dessiner ces données, histoire de vous convaincre que la PCA donne de "bons" résultats. La liste names
est simplement utilisée pour annoter nos cinq vecteurs.
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()
En regardant nos vecteurs originaux, nous verrons que les données [0] ("A") et les données [3] ("D") sont assez similaires à celles de données [1] ("B") et de données [2] (" C "). Ceci est reflété dans le tracé 2D de nos données transformées PCA.
Voici les options scikit-learn. Avec les deux méthodes, StandardScaler a été utilisé car PCA est effectué par échelle
Méthode 1: Demandez à scikit-learn de choisir le nombre minimum de composantes principales tel qu'au moins x% (90% dans l'exemple ci-dessous) de la variance soient conservés.
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_)
Méthode 2: choisissez le nombre de composants principaux (dans ce cas, 2 a été choisi)
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())
Source: https://towardsdatascience.com/pca-using-python-scikit-learn-e653f8989e60
biplot
en utilisant sklearn
et 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()
J'ai créé un petit script permettant de comparer les différents PCA. Voici une réponse:
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 est le pca dans la réponse de Mark .
pca_doug est le pca dans la réponse de doug .
Voici un exemple de sortie (mais le résultat dépend beaucoup de la taille des données et de pca_components. Il est donc recommandé d'exécuter votre propre test avec vos propres données. De plus, le pca de facebook est optimisé pour les données normalisées, il sera donc plus rapide et plus efficace. plus précis dans ce cas):
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
MODIFIER:
La fonction diffsnorm de fbpca calcule l'erreur de norme spectrale d'une décomposition de Schur.
Pour que def plot_pca(data):
fonctionne, il est nécessaire de remplacer les lignes
data_resc, data_orig = PCA(data)
ax1.plot(data_resc[:, 0], data_resc[:, 1], '.', mfc=clr1, mec=clr1)
avec des lignes
newData, data_resc, data_orig = PCA(data)
ax1.plot(newData[:, 0], newData[:, 1], '.', mfc=clr1, mec=clr1)