PCA проектирование и реконструкция в Scikit-Learn

Я могу выполнить PCA в scikit по коду ниже: X_train имеет 279180 строк и 104 столбца.

from sklearn.decomposition import PCA
pca = PCA(n_components=30)
X_train_pca = pca.fit_transform(X_train)

Теперь, когда я хочу проецировать собственные векторы на пространственное пространство, я должен сделать следующее:

""" Projection """
comp = pca.components_ #30x104
com_tr = np.transpose(pca.components_) #104x30
proj = np.dot(X_train,com_tr) #279180x104 * 104x30 = 297180x30

Но я не согласен с этим шагом, потому что Scikit документация говорит:

components_: array, [n_components, n_features]

Основные оси в пространстве объектов, представляющие направления максимальной дисперсии данных.

Мне кажется, что он уже проецируется, но когда я проверил исходный код, он возвращает только собственные векторы.

Каким образом можно спроектировать его?

В конечном счете, я собираюсь рассчитать MSE реконструкции.

""" Reconstruct """
recon = np.dot(proj,comp) #297180x30 * 30x104 = 279180x104

"""  MSE Error """
print "MSE = %.6G" %(np.mean((X_train - recon)**2))

Ответ 1

Ты можешь сделать

proj = pca.inverse_transform(X_train_pca)

Таким образом, вам не нужно беспокоиться о том, как сделать умножения.

После pca.fit_transform или pca.transform вы получаете pca.fit_transform, что обычно называют "нагрузками" для каждого образца, что означает, какой объем каждого компонента вам нужно описать лучше всего с использованием линейной комбинации components_ (главных осей в пространстве признаков).).

Проекция, на которую вы нацеливаетесь, возвращается в исходное пространство сигнала. Это означает, что вам нужно вернуться в пространство сигналов, используя компоненты и нагрузки.

Таким образом, есть три шага, чтобы устранить неоднозначность здесь. Здесь у вас есть шаг за шагом, что вы можете сделать с помощью объекта PCA и как он фактически рассчитывается:

  1. pca.fit оценивает компоненты (используя SVD на центрированном Xtrain):

    from sklearn.decomposition import PCA
    import numpy as np
    from numpy.testing import assert_array_almost_equal
    
    #Should this variable be X_train instead of Xtrain?
    X_train = np.random.randn(100, 50)
    
    pca = PCA(n_components=30)
    pca.fit(X_train)
    
    U, S, VT = np.linalg.svd(X_train - X_train.mean(0))
    
    assert_array_almost_equal(VT[:30], pca.components_)
    
  2. pca.transform рассчитывает нагрузки, как вы описываете

    X_train_pca = pca.transform(X_train)
    
    X_train_pca2 = (X_train - pca.mean_).dot(pca.components_.T)
    
    assert_array_almost_equal(X_train_pca, X_train_pca2)
    
  3. pca.inverse_transform получает проекцию на компоненты в интересующем вас сигнальном пространстве

    X_projected = pca.inverse_transform(X_train_pca)
    X_projected2 = X_train_pca.dot(pca.components_) + pca.mean_
    
    assert_array_almost_equal(X_projected, X_projected2)
    

Теперь вы можете оценить потери прогноза

loss = ((X_train - X_projected) ** 2).mean()

Ответ 2

В добавлении к сообщению @eickenberg, вот, как сделать pca реконструкцию изображений цифр:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn import decomposition

n_components = 10
image_shape = (8, 8)

digits = load_digits()
digits = digits.data

n_samples, n_features = digits.shape
estimator = decomposition.PCA(n_components=n_components, svd_solver='randomized', whiten=True)
digits_recons = estimator.inverse_transform(estimator.fit_transform(digits))

# show 5 randomly chosen digits and their PCA reconstructions with 10 dominant eigenvectors
indices = np.random.choice(n_samples, 5, replace=False)
plt.figure(figsize=(5,2))
for i in range(len(indices)):
    plt.subplot(1,5,i+1), plt.imshow(np.reshape(digits[indices[i],:], image_shape)), plt.axis('off')
plt.suptitle('Original', size=25)
plt.show()
plt.figure(figsize=(5,2))
for i in range(len(indices)):
    plt.subplot(1,5,i+1), plt.imshow(np.reshape(digits_recons[indices[i],:], image_shape)), plt.axis('off')
plt.suptitle('PCA reconstructed'.format(n_components), size=25)
plt.show()

enter image description here

enter image description here