Scikit-Learn PCA

Я использую входные данные отсюда (см. Раздел 3.1).

Я пытаюсь воспроизвести их ковариационную матрицу, собственные значения и собственные векторы, используя scikit-learn. Однако я не могу воспроизвести результаты, представленные в источнике данных. Я также видел эти входные данные в другом месте, но я не могу определить, является ли это проблемой с scikit-learn, моими шагами или источником данных.

data = np.array([[2.5,2.4],
                 [0.5,0.7],
                 [2.2,2.9],
                 [1.9,2.2],
                 [3.1,3.0],
                 [2.3,2.7],
                 [2.0,1.6],
                 [1.0,1.1],
                 [1.5,1.6],
                 [1.1,0.9],
                 ]) 

centered_data = data-data.mean(axis=0)
pca = PCA()
pca.fit(centered_data)
print(pca.get_covariance()) #Covariance Matrix

array([[ 0.5549,  0.5539],
   [ 0.5539,  0.6449]])

print(pca.explained_variance_ratio_) #Eigenvalues (normalized)

[ 0.96318131  0.03681869]

print(pca.components_) #Eigenvectors

[[-0.6778734  -0.73517866]
 [ 0.73517866 -0.6778734 ]]

Удивительно, но прогнозы совпадают с результатами из источника данных, описанного выше.

print(pca.transform(centered_data)) #Projections

array([[-0.82797019,  0.17511531],
   [ 1.77758033, -0.14285723],
   [-0.99219749, -0.38437499],
   [-0.27421042, -0.13041721],
   [-1.67580142,  0.20949846],
   [-0.9129491 , -0.17528244],
   [ 0.09910944,  0.3498247 ],
   [ 1.14457216, -0.04641726],
   [ 0.43804614, -0.01776463],
   [ 1.22382056,  0.16267529]])

Вот что я не понимаю:

  1. Почему ковариационная матрица отличается?
  2. Обновлено: как получить собственные значения из scikit-learn, которые еще не нормализованы?

2 ответа

Правильная ковариационная матрица этих данных:

numpy.cov(data.transpose())
array([[ 0.61655556,  0.61544444],
       [ 0.61544444,  0.71655556]])

Смещенная (т. Е. "Неправильная", использующая неверный термин нормализации и недооцененная дисперсия в наборе данных) ковариационная матрица:

numpy.cov(data.transpose(), bias=1)
array([[ 0.5549,  0.5539],
       [ 0.5539,  0.6449]])

Numpy знает, что вы должны центрировать свои данные - так что вам не нужно centered_data,

Компоненты PCA не являются собственными значениями 1:1.

Правильное разложение по собственным значениям:

numpy.linalg.eig(numpy.cov(data.transpose()))
(array([ 0.0490834 ,  1.28402771]),
 array([[-0.73517866, -0.6778734 ],
        [ 0.6778734 , -0.73517866]]))

Использование смещенной оценки дает различные собственные значения (опять же, недооценка дисперсии), но одинаковые собственные векторы:

(array([ 0.04417506,  1.15562494]), ...

Обратите внимание, что собственные векторы еще не отсортированы по наибольшим собственным значениям.

Как имя pca.explained_variance_ratio_ указывает, что это не собственные значения. Это соотношение. Если мы возьмем (смещенные, недооцененные) собственные значения и нормализуем их, чтобы получить сумму 1, мы получим

s/sum(s)
array([ 0.03681869,  0.96318131])

Так же pca.transform метод scipy, по-видимому, не применяется масштабирование. ИМХО, при использовании PCA также довольно распространено масштабирование каждого компонента, чтобы иметь единичную дисперсию. Это явно не относится к этому выводу. Тогда результат будет (с двумя перепутанными столбцами, я не удосужился изменить это)

s, e = numpy.linalg.eig(numpy.cov(data.transpose()))
o=numpy.argsort(s)[::-1]
(data-mean).dot(e[:,o]) / numpy.sqrt(s[o])
array([[-0.73068047, -0.79041795],
       [ 1.56870773,  0.64481466],
       [-0.87561043,  1.73495337],
       [-0.24198963,  0.58866414],
       [-1.47888824, -0.94561319],
       [-0.80567404,  0.79117236],
       [ 0.08746369, -1.57900372],
       [ 1.01008049,  0.20951358],
       [ 0.38657401,  0.08018421],
       [ 1.08001688, -0.73426743]])

(Как видите, PCA - это всего лишь три строки в numpy, так что вам не нужна функция для этого.)

Почему я думаю, что это правильный результат? Поскольку результирующий набор данных обладает свойством, что его ковариационная матрица является (за исключением ошибок округления) единичной матрицей. Без масштабирования ковариационная матрица numpy.diag(s[o]), Но можно также утверждать, что применяя масштабирование, я "потерял" информацию об отклонениях, которая была бы сохранена в противном случае.

По моему мнению, scipy использует неправильную (смещенную) ковариацию. numpy верно.

Но чаще всего это не имеет большого значения. При вышеуказанном соотношении смещение компенсируется. И если у вас большой набор данных, разница между использованием наивного 1/n и непредвзятый 1/(n-1) в конце концов становится небрежным. Но также разница заключается в практически нулевой стоимости процессора, поэтому вы также можете использовать объективную оценку отклонений.

Краткий ответ на (1) заключается в том, что когда вы применяли PCA к своим униженным данным, вы поворачивали их, и новое векторное пространство выражало новые случайные величины с различной ковариацией. Ответ (2): если вы хотите ненормализованные собственные значения, просто разложите собственную ковариационную матрицу ваших данных.

Больше информации:

Чтобы вычислить собственные значения с помощью scipy: http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eigvals.html

Вместо этого вы можете вычислить SVD матрицы данных (не ковариации) и посмотреть на единственные значения: http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.svd.html

Очевидно, у scikit-learn есть разные варианты SVD, которые вы можете попробовать.

Другие вопросы по тегам