PCA降维用于分类

3
我正在使用主成分分析(PCA)处理从不同CNN层中提取的特征。我已经从这里下载了降维工具箱。
我有11232张训练图像,每个图像的特征是6532。所以特征矩阵如下: 11232x6532。如果我想要前90%的特征,我可以轻松做到,并且使用SVM对缩减的数据进行训练的准确率为81.73%,效果还不错。然而,当我尝试测试数据时,该数据包含2408张图像,每个图像的特征也是6532。因此,测试数据的特征矩阵为2408x6532。在这种情况下,前90%特征的输出不正确,显示为2408x2408,测试准确率仅为25%。
如果不使用降维方法,训练准确率为82.17%,测试准确率为79%。
更新: 其中X是数据,no_dims是所需输出的维数。此PCA函数的输出是变量mappedX和结构体mapping
% Make sure data is zero mean
    mapping.mean = mean(X, 1);
    X = bsxfun(@minus, X, mapping.mean);

    % Compute covariance matrix
    if size(X, 2) < size(X, 1)
        C = cov(X);
    else
        C = (1 / size(X, 1)) * (X * X');        % if N>D, we better use this matrix for the eigendecomposition
    end

    % Perform eigendecomposition of C
    C(isnan(C)) = 0;
    C(isinf(C)) = 0;
    [M, lambda] = eig(C);

    % Sort eigenvectors in descending order
    [lambda, ind] = sort(diag(lambda), 'descend');
    if no_dims < 1
        no_dims = find(cumsum(lambda ./ sum(lambda)) >= no_dims, 1, 'first');
        disp(['Embedding into ' num2str(no_dims) ' dimensions.']);
    end
    if no_dims > size(M, 2)
        no_dims = size(M, 2);
        warning(['Target dimensionality reduced to ' num2str(no_dims) '.']);
    end
    M = M(:,ind(1:no_dims));
    lambda = lambda(1:no_dims);

    % Apply mapping on the data
    if ~(size(X, 2) < size(X, 1))
        M = bsxfun(@times, X' * M, (1 ./ sqrt(size(X, 1) .* lambda))');     % normalize in order to get eigenvectors of covariance matrix
    end
    mappedX = X * M;

    % Store information for out-of-sample extension
    mapping.M = M;
    mapping.lambda = lambda;

根据您的建议,我已经计算出了训练数据的向量。

numberOfDimensions = round(0.9*size(Feature,2));
[mapped_data, mapping] = compute_mapping(Feature, 'PCA', numberOfDimensions);

然后使用相同的向量进行测试数据:

mappedX_test = Feature_test * mapping.M;

准确率仍为32%。

通过减法解决:

Y = bsxfun(@minus, Feature_test, mapping.mean);
mappedX_test = Y * mapping.M;
1个回答

5
看起来您正在分别对训练数据和测试数据进行降维。在训练期间,您应该记住示例的主要得分或基向量。请记住,您正在使用训练数据基础上的一组新的正交轴找到数据的新表示形式。在测试过程中,您需要重复与训练数据完全相同的过程,因为您是根据这些基向量表示数据。因此,您使用训练数据的基向量来降低您的数据。你只获得一个 2408 x 2408 的矩阵,因为你正在对测试样本执行 PCA,不可能产生超出所涉及矩阵的秩(即 2408)的基向量。
保留训练阶段的基向量,并在测试阶段进行分类时,必须使用训练阶段的相同基向量。请记住,在 PCA 中,必须通过执行均值减法来使数据居中,然后再进行降维。在您的代码中,我们注意到基向量存储在 mapping.M 中,相关的均值向量存储在 mapping.mean 中。在进入测试阶段时,请确保使用来自训练阶段的 mapping.mean 对测试数据进行均值减法:
Y = bsxfun(@minus, Feature_test, mapping.mean);

一旦您拥有了数据,最后请继续进行降维处理:
mappedX_test = Y * mapping.M;

是的。正确的。降维是基于训练数据的,因为这是你正在构建的基础。测试数据应该使用相同的基向量进行降维。在测试数据上单独执行此操作是不正确的。 - rayryeng
@Addee 哈哈,我知道你错过了那一步 :) 我会更新我的帖子以便自我包含。很高兴你成功了! - rayryeng
@Addee 顺便问一下,现在你的准确率是多少,因为你已经正确地实现了它? - rayryeng
没有进行降维,测试准确率为79%,训练准确率为82%。有什么建议可以提高准确率吗? - Addee
2
@Addee 啊,这是PCA可能不起作用的情况之一。我建议你看看线性判别分析,因为你正在进行分类。LDA通过考虑最大化不同类别之间分离的基向量来执行降维。这基本上是执行有监督的降维。你正在使用的工具箱支持LDA,所以尝试使用它并查看你得到的性能。从LDA获得的基向量与PCA操作相同,因此除了将标志从“PCA”更改为“LDA”之外,几乎没有代码更改。 - rayryeng
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接