Python中的主成分分析:分析错误

时间:2014-04-05 18:37:53

标签: python pca

我正在Principal Component Analysis中实现Python人脸识别,而不使用PCAnumpy中已定义的OpenCV方法。但我的结果实际上是垃圾。

我在OpenCV的{​​{3}}阅读了文档和算法说明。但有些事情并不清楚。

  • 如果X = {x1, x2, ..., xn}那么我相信它不是计算协方差矩阵时使用的X矩阵?但是你要减去平均值等,如前两步所述。
  • 特征向量必须按降序对应于特征值进行排序。你是否必须在查看相应特征值的绝对值时进行排序?无论如何,当我绘制所有特征向量时,顺序不是主要问题,所以我可以相应地重新排列它们。我想我犯了一个分析错误。

我实施了以下内容:

MU = X.mean(axis=0)
for i in range(n):
    X[i,:] -= MU

S = (np.dot(X, X.T) / float(n))
#Hermitian (or symmetric) matrix.
eigenvalues, eigenvectors = numpy.linalg.eigh(S)
eigenvectors = numpy.dot(X.T, eigenvectors)
for i in range(n):
    eigenvectors[:,i] = normalize_vector(eigenvectors[:,i])

请注意,示例值存储在行而不是列中。因此X的形状为nxd,样本数为n,样本的维度为d

enter image description here

以上图片是参考。第一个是均值,以下三个是最大的特征向量。 下图是我的结果。第一个是均值,以下是某些顺序的所有特征向量。但它们似乎与结果不符。

cv2.PCACompute(X, 6)仍会产生更好的结果。

1 个答案:

答案 0 :(得分:1)

第一个问题很好回答here

对于第二个答案,你需要根据它们对应的特征值的值来对特征向量进行排序。为此,您可以使用python np.argsort()然后反转此顺序(argsort顺序从小到大):

indexes = np.argsort(eigenvalues)[::-1]
eigval = eigenvalues[indexes]
eigvec = eigenvectors[:,indexes]

检查您的代码,我发现了一些问题:

  1. 现在,你正在获得所有特征向量,你忽略了nb_components参数,你应该只选择你要求的向量。这是用

    完成的

    eigenvectors = eigenvectors[:,indexes][0:nb_components]

  2. 对于归一化向量(在pca函数内),你使用的是从0到n的for循环,但是如果你只被要求,比如3个特征向量,那么你只有3列。要解决此问题,请从0迭代到nb_components

  3. 除此之外,您的代码运作完美。我尝试了它只采用3个Principals组件,我得到6/6作为最终结果。在我看来,当从float转换为uint8以使用imshow时,显示特征向量的差异只是一个表示问题。

    关于负特征值,它只是eigh的问题。由于特征值显示方向的方差,我们关心绝对值,但如果我们改变符号,我们还必须改变"方向" (特征向量)。你可以将这个乘以负特征值及其相应的特征向量乘以-1.0(见this):

    s = np.where(eigenvalues < 0)
    eigenvalues[s] = eigenvalues[s] * -1.0
    eigenvectors[:,s] = eigenvectors[:,s] * -1.0
    

    您也可以使用numpy.linalg.svddocs)解决此问题,但速度应该比numpy.linalg.eigh慢。

    总结一下,这是我从你的代码中提出的代码(我在删除所有注释时将其缩短):

    def pca(X, nb_components=0):
        [n,d] = X.shape
        if (nb_components <= 0) or (nb_components>6):
            nb_components = n
    
        MU = X.mean(axis=0)
        for i in range(n):
            X[i,:] -= MU
    
        S = (np.dot(X, X.T) / float(n))
    
        eigenvalues, eigenvectors = np.linalg.eigh(S)
    
        s = np.where(eigenvalues < 0)
        eigenvalues[s] = eigenvalues[s] * -1.0
        eigenvectors[:,s] = eigenvectors[:,s] * -1.0
    
        indexes = np.argsort(eigenvalues)[::-1]
        eigenvalues = eigenvalues[indexes]
        eigenvectors = eigenvectors[:,indexes][:,0:nb_components]
    
        eigenvectors = np.dot(X.T, eigenvectors)
    
        for i in range(nb_components):
            eigenvectors[:,i] = normalize_vector(eigenvectors[:,i])
    
        return (eigenvalues, eigenvectors, MU)