수많은 기능 (> 10K)을위한 최고의 PCA 알고리즘?


54

이전에 StackOverflow에서 이것을 요청했지만 SO에 대한 답변을 얻지 못한 경우 여기에서 더 적절할 것 같습니다. 통계와 프로그래밍의 교차점에 있습니다.

PCA (Principal Component Analysis)를 수행하려면 코드를 작성해야합니다. 나는 잘 알려진 알고리즘을 탐색 하고이 알고리즘을 구현 했는데 NIPALS 알고리즘과 동일합니다. 처음 2-3 개의 주요 구성 요소를 찾는 데 효과적이지만 수백에서 수천 번 반복되는 수렴 속도가 매우 느린 것 같습니다. 필요한 내용은 다음과 같습니다.

  1. 알고리즘은 수백 개의 순서로 많은 수의 기능 (1 만 ~ 20,000 정도) 및 샘플 크기를 처리 할 때 효율적이어야합니다.

  2. 대상 언어가 아직 D가 아니기 때문에 적절한 선형 대수 / 행렬 라이브러리없이 합리적으로 구현할 수 있어야합니다. .

참고로, 동일한 데이터 세트에서 R은 모든 주요 구성 요소를 매우 빠르게 찾는 것처럼 보이지만 단일 값 분해를 사용하므로 직접 코딩하고 싶지는 않습니다.


2
많은 공개 SVD 알고리즘이 있습니다. en.wikipedia.org/wiki/…를 참조하십시오 . 당신은 그들 중 하나를 사용하거나 적응할 수 없습니까? 또한 R은 오픈 소스이며 GPL 라이센스 하에서 작동하는 경우 알고리즘을 빌리지 않는 이유는 무엇입니까?
Rob Hyndman

@Rob : 선형 대수 라이브러리를 실제로 작성하지 않고 GPL의 카피 레프트도 피하고 싶습니다. 또한 이전에 R 소스 코드의 비트와 조각을 살펴 보았으며 일반적으로 읽기 쉽지 않습니다.
dsimcha

4
뭔가 빠졌습니까? > 10K 이상의 기능이 있지만 <1K 샘플이 있습니까? 이것은 마지막 9K 구성 요소가 임의적임을 의미합니다. 첫 번째 구성 요소의 모든 1K를 원하십니까?
shabbychef

2
많은 수의 선형 대수 연구 덕분에 SVD를 구현할 필요가 없지만 행렬의 크기가 얼마나 크거나 작은 지, 희박 / 밀도가 있는지에 따라 선택할 수있는 방법이 많이 있습니다. 단수 값 또는 전체 단수 값과 왼쪽 / 오른쪽 단수 벡터를 원합니다. 알고리즘은 IMHO를 이해하기가 어렵지 않습니다.
JM은 통계학자가 아닙니다.

PCA를 왜하고 싶은지 말씀해 주시겠습니까?
로빈 지라드

답변:


27

"Halko, N., Martinsson, PG, Shkolnisky, Y., & Tygert, M. (2010)"에 제시된대로 Randomized SVD를 구현했습니다. 대규모 데이터 세트의 주요 구성 요소 분석 알고리즘 Arxiv preprint arXiv : 1007.5510, 0526. 2011 년 4 월 1 일에 http://arxiv.org/abs/1007.5510 에서 검색 됨 . " 잘린 SVD를 얻으려면 MATLAB의 svd 변형보다 훨씬 빠르게 작동합니다. 여기에서 얻을 수 있습니다 :

function [U,S,V] = fsvd(A, k, i, usePowerMethod)
% FSVD Fast Singular Value Decomposition 
% 
%   [U,S,V] = FSVD(A,k,i,usePowerMethod) computes the truncated singular
%   value decomposition of the input matrix A upto rank k using i levels of
%   Krylov method as given in [1], p. 3.
% 
%   If usePowerMethod is given as true, then only exponent i is used (i.e.
%   as power method). See [2] p.9, Randomized PCA algorithm for details.
% 
%   [1] Halko, N., Martinsson, P. G., Shkolnisky, Y., & Tygert, M. (2010).
%   An algorithm for the principal component analysis of large data sets.
%   Arxiv preprint arXiv:1007.5510, 0526. Retrieved April 1, 2011, from
%   http://arxiv.org/abs/1007.5510. 
%   
%   [2] Halko, N., Martinsson, P. G., & Tropp, J. A. (2009). Finding
%   structure with randomness: Probabilistic algorithms for constructing
%   approximate matrix decompositions. Arxiv preprint arXiv:0909.4061.
%   Retrieved April 1, 2011, from http://arxiv.org/abs/0909.4061.
% 
%   See also SVD.
% 
%   Copyright 2011 Ismail Ari, http://ismailari.com.

    if nargin < 3
        i = 1;
    end

    % Take (conjugate) transpose if necessary. It makes H smaller thus
    % leading the computations to be faster
    if size(A,1) < size(A,2)
        A = A';
        isTransposed = true;
    else
        isTransposed = false;
    end

    n = size(A,2);
    l = k + 2;

    % Form a real n×l matrix G whose entries are iid Gaussian r.v.s of zero
    % mean and unit variance
    G = randn(n,l);


    if nargin >= 4 && usePowerMethod
        % Use only the given exponent
        H = A*G;
        for j = 2:i+1
            H = A * (A'*H);
        end
    else
        % Compute the m×l matrices H^{(0)}, ..., H^{(i)}
        % Note that this is done implicitly in each iteration below.
        H = cell(1,i+1);
        H{1} = A*G;
        for j = 2:i+1
            H{j} = A * (A'*H{j-1});
        end

        % Form the m×((i+1)l) matrix H
        H = cell2mat(H);
    end

    % Using the pivoted QR-decomposiion, form a real m×((i+1)l) matrix Q
    % whose columns are orthonormal, s.t. there exists a real
    % ((i+1)l)×((i+1)l) matrix R for which H = QR.  
    % XXX: Buradaki column pivoting ile yapılmayan hali.
    [Q,~] = qr(H,0);

    % Compute the n×((i+1)l) product matrix T = A^T Q
    T = A'*Q;

    % Form an SVD of T
    [Vt, St, W] = svd(T,'econ');

    % Compute the m×((i+1)l) product matrix
    Ut = Q*W;

    % Retrieve the leftmost m×k block U of Ut, the leftmost n×k block V of
    % Vt, and the leftmost uppermost k×k block S of St. The product U S V^T
    % then approxiamtes A. 

    if isTransposed
        V = Ut(:,1:k);
        U = Vt(:,1:k);     
    else
        U = Ut(:,1:k);
        V = Vt(:,1:k);
    end
    S = St(1:k,1:k);
end

테스트하려면 동일한 폴더에 이미지를 만드십시오 (큰 매트릭스와 마찬가지로 매트릭스를 직접 만들 수 있습니다)

% Example code for fast SVD.

clc, clear

%% TRY ME
k = 10; % # dims
i = 2;  % # power
COMPUTE_SVD0 = true; % Comment out if you do not want to spend time with builtin SVD.

% A is the m×n matrix we want to decompose
A = im2double(rgb2gray(imread('test_image.jpg')))';

%% DO NOT MODIFY
if COMPUTE_SVD0
    tic
    % Compute SVD of A directly
    [U0, S0, V0] = svd(A,'econ');
    A0 = U0(:,1:k) * S0(1:k,1:k) * V0(:,1:k)';
    toc
    display(['SVD Error: ' num2str(compute_error(A,A0))])
    clear U0 S0 V0
end

% FSVD without power method
tic
[U1, S1, V1] = fsvd(A, k, i);
toc
A1 = U1 * S1 * V1';
display(['FSVD HYBRID Error: ' num2str(compute_error(A,A1))])
clear U1 S1 V1

% FSVD with power method
tic
[U2, S2, V2] = fsvd(A, k, i, true);
toc
A2 = U2 * S2 * V2';
display(['FSVD POWER Error: ' num2str(compute_error(A,A2))])
clear U2 S2 V2

subplot(2,2,1), imshow(A'), title('A (orig)')
if COMPUTE_SVD0, subplot(2,2,2), imshow(A0'), title('A0 (svd)'), end
subplot(2,2,3), imshow(A1'), title('A1 (fsvd hybrid)')
subplot(2,2,4), imshow(A2'), title('A2 (fsvd power)')

빠른 SVD

크기가 635 * 483 인 이미지를 바탕 화면에서 실행하면

Elapsed time is 0.110510 seconds.
SVD Error: 0.19132
Elapsed time is 0.017286 seconds.
FSVD HYBRID Error: 0.19142
Elapsed time is 0.006496 seconds.
FSVD POWER Error: 0.19206

보다시피, 값이 낮 으면 kMatlab SVD를 사용하는 것보다 10 배 이상 빠릅니다. 그런데 테스트 기능을 위해 다음과 같은 간단한 기능이 필요할 수 있습니다.

function e = compute_error(A, B)
% COMPUTE_ERROR Compute relative error between two arrays

    e = norm(A(:)-B(:)) / norm(A(:));
end

SVD를 사용하여 구현하는 것이 간단하기 때문에 PCA 방법을 추가하지 않았습니다. 이 링크 를 확인하여 관계를 확인할 수 있습니다 .


12

몇 가지 옵션을 사용해보십시오.

1- Penalized Matrix 분해 . 희소성을 얻기 위해 u와 v에 약간의 페널티 제약 조건을 적용합니다. 게놈 데이터에 사용 된 빠른 알고리즘

Whitten Tibshirani를 참조하십시오. 그들은 또한 R-pkg를 가지고 있습니다. "주요 성분을 희소 화하고 표준 상관 분석을 적용하는 애플리케이션을 갖춘 불이익을받은 매트릭스 분해."

2- 무작위 SVD . SVD는 마스터 알고리즘이므로 특히 탐색 적 분석에 대해 매우 빠른 근사가 바람직 할 수 있습니다. 무작위 SVD를 사용하면 거대한 데이터 세트에서 PCA를 수행 할 수 있습니다.

Martinsson, Rokhlin 및 Tygert "매트릭스 분해를위한 무작위 알고리즘"을 참조하십시오. Tygert는 매우 빠른 PCA 구현을위한 코드를 가지고 있습니다.

아래는 R에서 무작위 SVD의 간단한 구현입니다.

ransvd = function(A, k=10, p=5) {
  n = nrow(A)
  y = A %*% matrix(rnorm(n * (k+p)), nrow=n)
  q = qr.Q(qr(y))
  b = t(q) %*% A
  svd = svd(b)
  list(u=q %*% svd$u, d=svd$d, v=svd$v)
}

페널티 매트릭스 분해의 경우 +1 그 패키지는 정말 놀랍습니다. 사람들이 인용을 찾는 데 어려움을 겪을 경우를 대비하여 "주목"이라는 철자를 언급했을 것입니다. 마지막으로 OP는 R로 작성된 것을 원하지 않지만 본질적으로 대형 SVD 패키지에는 속도를 위해 C, C ++ 또는 Fortran 백엔드가 있다고 말했다.
David J. Harris


3

기능 수 (P)가 아닌 예제 수 (N)에 따라 시간 / 공간이 복잡한 커널 PCA를 사용 하는 것이 좋습니다. 설정 (P >> N)에 더 적합하다고 생각합니다. 커널 PCA는 기본적으로 큰 P에 대해 다루기가 어려운 PxP 공분산 행렬이 아니라 NxN 커널 행렬 (데이터 포인트 간 유사성 행렬)과 함께 작동합니다. 커널 PCA의 또 다른 장점은 비선형 투영법을 배울 수 있다는 것입니다 적절한 커널과 함께 사용하는 경우에도 마찬가지입니다. 커널 PCA에 대한이 백서를 참조하십시오 .


2

XX ^ T가 아닌 X ^ TX의 고유 분해를 계산하여 PCA를 수행 한 다음 PC를 얻기 위해 변환하는 것이 가능하다고 생각합니다. 그러나 나는 세부 사항을 기억하지 못하지만 Jolliffe의 (우수한) 책에 있으며 다음에 일할 때 찾아 볼 것입니다. 다른 알고리즘을 사용하는 대신 C의 Numerical Methods에서 선형 대수 루틴을 음역합니다.


5
좋은 슬픔 ... 공분산 행렬을 구성하는 것이 SVD에 가장 좋은 방법은 아닙니다. math.SE에서 공분산 행렬을 명시 적으로 형성하는 것이 좋은 생각이 아닌 이유의 예를 표시했습니다. math.stackexchange.com/questions/3869/3871#3871 .
JM은 통계학자가 아닙니다.

1

Fisher 등부트 스트랩 방법 도 있으며 , 수백 개의 고차원 샘플을 위해 설계되었습니다.

이 방법의 주요 아이디어는 "리샘플링은 저 차원 변환"입니다. 따라서 적은 수의 고차원 샘플이있는 경우 샘플 수보다 더 많은 주요 구성 요소를 얻을 수 없습니다. 따라서 샘플을 비유적인 기준으로 간주하고 이러한 벡터에 의해 확장 된 선형 부분 공간에 데이터를 투영하고이 작은 부분 공간 내에서 PCA를 계산하는 것이 합리적입니다. 또한 모든 샘플이 메모리에 저장되지 않는 경우를 처리하는 방법에 대한 자세한 내용도 제공합니다.


0

Sam Roweis의 논문, PCA 및 SPCA를위한 EM 알고리즘을 참조하십시오 .


Wikipedia 알고리즘은 이것을 인용하며 한 번에 하나의 주요 구성 요소를 찾는 경우와 동일합니다.
dsimcha

좋아, 나는 지금 링크를 본다. 이것은 매우 간단한 접근 방식이며 Wikipedia의 언급처럼이 기본 아이디어에 대한 발전이 있습니다. 그러나, 당신은 일종의 트레이드 오프 (이 경우 컨버전스)를 처리해야합니다. 여기에 올바른 질문이 있는지 궁금합니다. D에 대한 linalg 라이브러리에 대한 바인딩이 실제로 없습니까?
ars
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.