Анализ основных компонентов (PCA) в Python
У меня есть массив (26424 x 144), и я хочу выполнить PCA над ним с помощью Python. Однако в интернете нет конкретного места, которое объясняет, как достичь этой задачи (есть некоторые сайты, которые просто делают PCA по своему усмотрению - нет обобщенного способа сделать так, чтобы я мог найти). Любой, у кого есть хоть какая-то помощь, отлично справится.
9 ответов:
вы можете найти функцию PCA в модуле matplotlib:
import numpy as np from matplotlib.mlab import PCA data = np.array(np.random.randint(10,size=(10,3))) results = PCA(data)
результаты будут хранить различные параметры PCA. Это из части mlab matplotlib, которая является уровнем совместимости с синтаксисом MATLAB
изменить: на блоге nextgenetics Я нашел замечательную демонстрацию того, как выполнять и отображать PCA с модулем matplotlib mlab, получайте удовольствие и проверьте этот блог!
я опубликовал свой ответ, хотя другой ответ уже принят; принятый ответ зависит от устаревшие функции; кроме того, эта устаревшая функция основана на Сингулярное Разложение (SVD), который (хотя и совершенно действителен) является гораздо более интенсивным для памяти и процессора из двух общих методов расчета PCA. Это особо актуально здесь потому, что размер массива данных в ФП. Используя ковариацию основе PCA, массив, используемый в потоке вычислений, просто 144 x 144, а не 26424 x 144 (размер исходного массива данных).
вот простая рабочая реализация PCA с использованием linalg модуль составляющей. Поскольку эта реализация сначала вычисляет ковариационную матрицу, а затем выполняет все последующие вычисления в этом массиве, она использует гораздо меньше памяти, чем SVD-PCA.
(модуль linalg в включает в себя также можно использовать без изменений в коде ниже, кроме оператора import, который будет от импорта numpy linalg как LA.)
два ключевых шага в этой реализации PCA являются:
расчета матрица ковариации; и
взяв eivenvectors & собственные этой ков матрица
в функции ниже, параметр dims_rescaled_data относится к желаемому количеству измерений в масштабирование матрица данных; этот параметр имеет значение по умолчанию только два измерения, но ниже код не ограничивается двумя, но это может быть любой значение меньше, чем номер столбца исходных данных матрица.
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)
график ниже представляет собой визуальное представление этой функции PCA на данных iris. Как вы можете видеть, 2D-преобразование четко отделяет класс I от класса II и класса III (но не класс II от класса III, что на самом деле требует другого измерения).
другой Python PCA с помощью numpy. Та же идея, что и @doug, но эта не сработала.
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()
что дает то же самое, что и гораздо короче
from sklearn.decomposition import PCA def pca2(data, pc_count = None): return PCA(n_components = 4).fit_transform(data)
это работа для
numpy
.и вот учебник, демонстрирующий, как pincipal анализ компонента могут быть выполнены с помощью
numpy
встроенные модули, такие какmean,cov,double,cumsum,dot,linalg,array,rank
.http://glowingpython.blogspot.sg/2011/07/principal-component-analysis-with-numpy.html
обратите внимание, что
scipy
также имеет длинное объяснение здесь - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/utils/extmath.py#L105С
scikit-learn
библиотека, имеющая больше примеров кода - https://github.com/scikit-learn/scikit-learn/blob/babe4a5d0637ca172d47e1dfdd2f6f3c3ecb28db/scikits/learn/utils/extmath.py#L105
вот параметры scikit-learn. С обоими методами, StandardScaler был использован, потому что PCA осуществляется по шкале
метод 1: у scikit-learn выберите минимум количество главных компонентов, таких что сохраняется по крайней мере x% (90% в примере ниже) дисперсии.
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_)
Метод 2: Выберите количество основных компонентов (в этом случае было выбрано 2)
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())
источник: https://towardsdatascience.com/pca-using-python-scikit-learn-e653f8989e60
обновление:
matplotlib.mlab.PCA
С момента выпуска 2.2 (2018-03-06) действительно не рекомендуется.
библиотекаmatplotlib.mlab.PCA
(в ответ) составляет не не рекомендуется. Поэтому для всех людей, прибывающих сюда через Google, я опубликую полный рабочий пример, протестированный с Python 2.7.используйте следующий код с осторожностью, поскольку он использует теперь устаревшую библиотеку!
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)
теперь в ' pca.Г-это исходная матрица данных в терминах базисных векторов главных компонент. Более подробную информацию об объекте PCA можно найти здесь.
>>> 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]])
можно использовать
matplotlib.pyplot
чтобы нарисовать эти данные, просто чтобы убедить себя, что PCA дает "хорошие" результаты. Элементnames
список просто используется для аннотирования наших пяти векторов.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()
глядя на наши исходные векторы, мы увидим, что данные[0] ("A") и данные[3] ("D") довольно похожи, как и данные[1] ("B") и данные[2] ("С.)" Это отражено в 2D графике наших преобразованных данных PCA.
Я сделал небольшой скрипт для сравнения различных PCAs появился в качестве ответа здесь:
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-это pca в ответе Марка.
pca_doug-это pca в ответе дуга.
вот пример вывода (но результат очень сильно зависит от размера данных и pca_components, так что я бы рекомендовал запустить свой собственный тест с вашими собственными данными. Кроме того, pca facebook оптимизирован для нормализованных данных, поэтому он будет быстрее и точнее в таком случае):
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:
The diffsnorm функция от fbpca вычисляет спектрально-нормальную ошибку разложения Шура.
в дополнение ко всем другим ответам, вот некоторый код для построения
biplot
С помощьюsklearn
и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()