我的PCA出了什么问题?

时间:2011-01-26 03:50:01

标签: python numpy machine-learning linear-algebra pca

我的代码:

from numpy import *

def pca(orig_data):
    data = array(orig_data)
    data = (data - data.mean(axis=0)) / data.std(axis=0)
    u, s, v = linalg.svd(data)
    print s #should be s**2 instead!
    print v

def load_iris(path):
    lines = []
    with open(path) as input_file:
        lines = input_file.readlines()
    data = []
    for line in lines:
        cur_line = line.rstrip().split(',')
        cur_line = cur_line[:-1]
        cur_line = [float(elem) for elem in cur_line]
        data.append(array(cur_line))
    return array(data)

if __name__ == '__main__':
    data = load_iris('iris.data')
    pca(data)

虹膜数据集:http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data

输出:

[ 20.89551896  11.75513248   4.7013819    1.75816839]
[[ 0.52237162 -0.26335492  0.58125401  0.56561105]
 [-0.37231836 -0.92555649 -0.02109478 -0.06541577]
 [ 0.72101681 -0.24203288 -0.14089226 -0.6338014 ]
 [ 0.26199559 -0.12413481 -0.80115427  0.52354627]]

期望的输出:
特征值 - [2.9108 0.9212 0.1474 0.0206]
主成分 - Same as I got but transposed所以我猜是好的

另外,linalg.eig函数的输出是什么?根据维基百科上的PCA描述,我应该这样:

cov_mat = cov(orig_data)
val, vec = linalg.eig(cov_mat)
print val

但它与我在网上找到的教程中的输出并不完全匹配。另外,如果我有4个维度,我认为我应该有4个特征值而不是像eig给我的150个特征值。我做错了吗?

编辑:我注意到值相差150,这是数据集中元素的数量。此外,特征值应该加上等于维数,在这种情况下,4。我不明白为什么会发生这种差异。如果我简单地将特征值除以len(data),我可以得到我想要的结果,但我不明白为什么。无论哪种方式,特征值的比例都没有改变,但它们对我很重要,所以我想了解发生了什么。

4 个答案:

答案 0 :(得分:10)

你分解了错误的矩阵。

主成分分析需要操纵特征向量/特征值 协方差矩阵 ,而不是数据本身。从m×n数据矩阵创建的协方差矩阵将是m×m矩阵,沿主对角线具有一个矩阵。

您确实可以使用 cov 功能,但需要进一步处理数据。使用类似的功能可能会更容易一些, corrcoef

import numpy as NP
import numpy.linalg as LA

# a simulated data set with 8 data points, each point having five features
data = NP.random.randint(0, 10, 40).reshape(8, 5)

# usually a good idea to mean center your data first:
data -= NP.mean(data, axis=0)

# calculate the covariance matrix 
C = NP.corrcoef(data, rowvar=0)
# returns an m x m matrix, or here a 5 x 5 matrix)

# now get the eigenvalues/eigenvectors of C:
eval, evec = LA.eig(C)

为了得到特征向量/特征值,我没有使用SVD分解协方差矩阵, 不过,你当然可以。我的偏好是使用NumPy(或SciPy)中的 eig 来计算它们 LA模块 - 它比 svd 更容易使用,返回值是特征向量 和特征值本身,没有别的。相比之下,如您所知, svd 不会直接返回这些内容。

当然,SVD功能会分解任何矩阵,而不仅仅是方形矩阵( eig 功能受限);然而,当做PCA时,你总会有一个方阵来分解, 不管你的数据是什么形式。这很明显,因为矩阵你 在PCA中分解的是协方差矩阵,根据定义,它总是方形的 (即,列同样是原始矩阵的各个数据点) 对于行,每个单元格是这两个点的协方差,如证明的那样 通过主对角线下的那些 - 给定的数据点与其自身具有完美的协方差。)

答案 1 :(得分:3)

SVD(A)返回的左奇异值是AA ^ T的特征向量。

数据集A的协方差矩阵为:1 /(N-1)* AA ^ T

现在,当你使用SVD进行PCA时,你必须将A矩阵中的每个条目除以(N-1),这样就可以得到具有正确尺度的协方差的特征值。

在你的情况下,N = 150并且你没有进行这种划分,因此存在差异。

详细解释here

答案 2 :(得分:2)

(你能问一个问题吗?或者至少单独列出你的问题。你的帖子就像意识流一样,因为你不是在问一个问题。)

  1. 您可能错误地使用了cov,而不是首先转置矩阵。如果cov_mat是4乘4,则eig将生成四个特征值和四个特征向量。

  2. 注意SVD和PCA虽然相关,但并不完全相同。设X为4×150的观测矩阵,其中每个4元素列是单个观测值。然后,以下是等效的:

    一个。左边的奇异向量X,

    湾X的主要组成部分,

    ℃。 X X ^ T的特征向量。

    此外,X X ^ T的特征值等于X的奇异值的平方。为了看到所有这些,令X具有SVD X = QSV ^ T,其中S是奇异值的对角矩阵。然后考虑特征分解D = Q ^ T X X ^ T Q,其中D是特征值的对角矩阵。用其SVD替换X,看看会发生什么。

答案 3 :(得分:0)