Ответ 1
Корректная ковариационная матрица этих данных:
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, по-видимому, не применяется масштабирование. IMHO, при использовании 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)
в конечном итоге становится небрежным. Но также разница достигается при нулевой стоимости процессора, поэтому вы можете также использовать объективную оценку дисперсии.