9

我的代码:

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

4 回答 4

10

你分解了错误的矩阵。

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

您确实可以使用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)的 LA 模块中使用eig来计算它们——它比svd更容易使用,返回值是特征向量和特征值本身,仅此而已。相比之下,如您所知,svd不会直接返回这些。

假设SVD 函数将分解任何矩阵,而不仅仅是方形矩阵(eig函数仅限于此);但是,在进行 PCA 时,无论您的数据采用何种形式,您总是需要分解一个方阵。这很明显,因为您在 PCA 中分解的矩阵是一个协方差矩阵,根据定义,它始终是方阵(即,列是原始矩阵的各个数据点,行也是如此,每个单元格都是这两个点的协方差,正如主对角线下方的那些点所证明的那样——给定的数据点与自身具有完美的协方差) .

于 2011-01-26T09:48:21.903 回答
3

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

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

现在,当您使用 SVD 进行 PCA 时,您必须将 A 矩阵中的每个条目除以 (N-1),以便获得具有正确比例的协方差的特征值。

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

这在这里详细解释

于 2012-03-19T16:30:26.970 回答
2

(你能问一个问题吗?或者至少单独列出你的问题。你的帖子读起来像是一股意识流,因为你没有问一个问题。)

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

  2. 注意 SVD 和 PCA 虽然相关,但并不完全相同。令 X 为 4×150 的观察矩阵,其中每个 4 元素列是一个观察。那么,以下是等价的:

    一种。X 的左奇异向量,

    湾。X 的主成分,

    C。XX^T 的特征向量。

    此外,XX^T 的特征值等于 X 的奇异值的平方。要了解这一切,让 X 具有 SVD X = QSV^T,其中 S 是奇异值的对角矩阵。然后考虑特征分解 D = Q^TXX^TQ,其中 D 是特征值的对角矩阵。用它的 SVD 替换 X,看看会发生什么。

于 2011-01-26T06:00:02.417 回答
0

已解决的问题:Python 中的主成分分析

于 2011-01-26T04:08:05.577 回答