一个PCA加速技巧

EVD-PCA

PCA推导:PCA主成分分析法浅理解
一个PCA加速技巧_第1张图片
具体数值如10304×10304是我机器学习课程实验的数据集参数,这里关注数字量级即可。

code

% EVD-PCA数据降维
% input: D×N output:K×N
function [Z, K] = EVD_PCA(X, K, weight)
    fprintf('Running EVD-PCA dimensionality reduction...\n');
    if exist('eigenData.mat', 'file') == 0
        [~, N] = size(X);
        %% Step 1: Center the data
%         mu  = mean(X);
%         X = X - mu;   !err
        mu  = mean(X, 2);
        X = X - mu * ones(1, N);
        %% Step 2: Compute the covariance matrix
        S = X * X' / N; % D×D
%         size(S)
        %% Step 3: Do an eigendecomposition of S
        [V, D] = eig(S);    % !time-consuming
        % S*V=V*D,其中D为特征值的对角矩阵,V对应列为特征向量
        % (D×D)*(D×E)=(D×E)*(E×E),其中E为特征值个数,D为原数据维度(区分对角矩阵D)
        
        %% Step 4: Take first K leading eigenvector
        eigenVal = diag(D); % 特征值序列
        [~, sortedIndex] = sort(eigenVal, 'descend');
        eigenVec = V(:, sortedIndex);   % 对应特征向量构筑矩阵
        eigenVal = eigenVal(sortedIndex);
        save('eigenData.mat', 'eigenVec', 'eigenVal');
    else 
        load('eigenData.mat');
    end
    %% 检查是否传入有效K,否则基于weight动态定义K
    % 前K个特征值之和占特征值之和的比例达到weight
    if K < 0
       sumVal = sum(eigenVal);
       for i = 1 : length(eigenVal)
           newRate = sum(eigenVal(1 : i), 1) / sumVal;
           if newRate >= weight
               K = i; break;
           end
       end
       fprintf('Dynamically define K to %d\n', K);
    end
    U = eigenVec(:, 1 : K); % (D×K)
    
    %% Step 5: Calc the final K dim. projection of data
    Z = U' * X; % (K×N)=(K×D)*(D×N)
    
    fprintf('EVD-PCA done\n');
end

SVD-PCA

一个PCA加速技巧_第2张图片
以上是我发现的一个小技巧,并通过测试发现,SVD-PCA方法准确率和标准EVD-PCA方法几乎相同,而效率大大提升!

code

% SVD-PCA数据降维
% input: D×N output:K×N
function [Z] = SVD_PCA(X, K)
    fprintf('Running SVD-PCA dimensionality reduction...\n');
    [D, N] = size(X);    % D:feature dimension
    %% Step 1: Center the data
    mu  = mean(X, 2);
    X = X - mu * ones(1, N);

    %% Step 2: Compute the A^{T}A
    Mat = X' * X;
    %% Step 3: Do an eigendecomposition of A^{T}A
    % 利用左奇异值矩阵U进行特征维度压缩,即减少X的行数
    [V, S] = eig(Mat);  % N×N
    %% Step 4: Take first K leading eigenvector of A^{T}A then build 
    %% Left single matrix U
    S = diag(S);
    [S, si] = sort(S, 'descend');

    eigenVec = zeros(N, K);
    eigenVal = zeros(1, K);
    for i = 1 : K
        eigenVec(:, i) = V(:, si(i));
        eigenVal(i) = S(i);
    end
    
    rU = zeros(D, K);   % reconstructed matrix U
    for i = 1 : K
        rU(:, i) = X * eigenVec(:, i) / sqrt(eigenVal(i));    % 奇异值≈sqrt(特征值)
    end
%     save('svdData', 'eigenVec', 'eigenVal', 'rU');
    
    %% Step 5: Calc the final K dim. projection of data
    Z = rU' * X; % (K×N)=(K×D)*(D×N)
    
    fprintf('SVD-PCA done\n');
end

Comparison

Accuracy

K值 SVD-PCA(×100%) EVD-PCA(×100%)
1 0.160000000000000 0.175000000000000
2 0.385000000000000 0.368750000000000
4 0.740000000000000 0.756250000000000
8 0.930000000000000 0.918750000000000
16 0.960000000000000 0.937500000000000
32 0.970000000000000 0.975000000000000
48 0.965000000000000 0.975000000000000
64 0.955000000000000 0.981250000000000
80 0.950000000000000 0.975000000000000
96 0.955000000000000 0.968750000000000

Time consumption

一个PCA加速技巧_第3张图片
一个PCA加速技巧_第4张图片
可以看到两种方法10次不同K值PCA部分的总用时分别为1.482s162.713s,而且实际上后者利用了文件存储的结果。效率的差异源于对两个不同矩阵(10304×10304 vs. 400×400)做evd.

Conclusion

由于测试集大小在120-200之间,以上准确率可以认为几乎相同。因此我们可以得出结论:SVD-PCA在该人脸数据集表现更优。
或者说在 D ≫ N D\gg N DN的情况下通过SVD做协方差矩阵 S S S的特征值分解是可行的。

你可能感兴趣的:(ML,算法,数据降维,PCA)