膨大な数の機能(> 10K)に最適なPCAアルゴリズム?


54

以前にStackOverflowでこれを尋ねましたが、SOで何の回答も得られなかったことを考えると、ここでの方が適切かもしれません。統計とプログラミングの交差点にあります。

PCA(主成分分析)を行うためのコードを書く必要があります。私はよく知られたアルゴリズムを閲覧し、これを実装しました。これは、私が知る限り、NIPALSアルゴリズムと同等です。最初の2〜3個の主成分を見つけるのに適していますが、収束が非常に遅くなるようです(数百から数千回の繰り返し)。必要なものの詳細は次のとおりです。

  1. アルゴリズムは、膨大な数の機能(10,000〜20,000のオーダー)と数百のオーダーのサンプルサイズを扱う場合に効率的でなければなりません。

  2. ターゲット言語はDであるため、まともな線形代数/マトリックスライブラリがなくても合理的に実装可能でなければなりません。Dはまだ1つもありません。 。

補足として、同じデータセットでRはすべての主成分を非常に高速に見つけるように見えますが、特異値分解を使用します。これは自分でコーディングしたいものではありません。


2
多くのパブリックSVDアルゴリズムがあります。en.wikipedia.org/wiki/…を参照してください。それらのいずれかを使用または適応することはできませんか?また、Rはオープンソースであり、GPLライセンスの下にあるので、仕事をするならアルゴリズムを借りてみませんか?
ロブハインドマン

@Rob:線形代数ライブラリを実際に書くことは避けたいし、GPLのコピーレフトも避けたい。また、私はRソースコードの断片を以前に見てきましたが、一般的には読みにくいです。
dsimcha

4
何か不足していますか?10Kを超える機能がありますが、サンプルは1K未満ですか?つまり、最後の9Kコンポーネントは任意です。最初のコンポーネントのすべての1Kが必要ですか?
みすぼらしいシェフ

2
いずれにせよ、SVDを実装することから逃れることはできませんが、多くの数値線形代数の研究のおかげで、マトリックスの大きさ/小ささ、スパース/デンス、または特異値のみ、または特異値と左/右特異ベクトルの完全なセットが必要です。アルゴリズムは、IMHOを理解するのがそれほど難しくありません。
JMは統計学者ではない

PCAを行う理由を教えてください。
ロビンギラード

回答:


27

「Halko、N.、Martinsson、PG、Shkolnisky、Y.、&Tygert、M.(2010)」に記載されているように、ランダム化SVDを実装しました。大規模なデータセットの主成分分析のためのアルゴリズム。 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- ペナルティマトリックス分解。スパース性を得るには、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バックエンドを持つだろう。
デビッドJ.ハリス

4

多分あなたはLanczosアルゴリズムを使いたいように思えます。それに失敗した場合は、Golub&Van Loanに相談することをお勧めしますテキストからSVDアルゴリズム(すべての言語のSML)をコーディングしたことがありますが、それはかなりうまくいきました。


3

機能の数(P)ではなく、例の数(N)に依存する時間/空間の複雑さを持つカーネルPCAを試してみることをお勧めします。カーネルPCAは基本的に、大きなPでは扱いにくいPxP共分散行列ではなく、NxNカーネル行列(データポイント間の類似性の行列)で動作します。カーネルPCAのもう1つの良い点は、非線形射影を学習できることです適切なカーネルで使用する場合も同様です。カーネルPCAに関するこのペーパーを参照してください。


2

私は、XX ^ TではなくX ^ TXの固有分解を計算してPCAを実行し、変換してPCを取得することが可能であることを思い出すようです。しかし、詳細はすぐに覚えることはできませんが、それはジョリッフの(優秀な)本に載っていて、次に仕事をするときに調べます。他のアルゴリズムを使用するのではなく、Cの数値法などの線形代数ルーチンを音訳します。


5
良い悲嘆...共分散行列を構築することは、SVDにとって最良の方法ではありません。:私は、明示的に共分散行列を形成することmath.SEで良いアイデアではない理由の例表示math.stackexchange.com/questions/3869/3871#3871を
JMは、統計学者ではありません

1

Fisherなどによる高次元の数百のサンプル用に設計さブートストラップ法もあります。

このメソッドの主なアイデアは、「リサンプリングは低次元の変換です」と定式化されています。したがって、少数(数百)の高次元サンプルがある場合、サンプルの数より多くの主成分を取得することはできません。したがって、サンプルをthe約ベースとみなし、これらのベクトルがまたがる線形部分空間にデータを投影し、この小さな部分空間内でPCAを計算することは理にかなっています。また、すべてのサンプルがメモリに保存されているわけではない場合の対処方法についても詳しく説明しています。


0

Sam Roweisの論文、PCAおよびSPCAのEMアルゴリズムを参照してください。


ウィキペディアのアルゴリズムはこれを引用し、一度に1つの主成分を見つける場合のこれと同等です。
dsimcha

OK、リンクが表示されました。これはかなり単純なアプローチであり、Wikipediaが言及しているように、この基本的な考え方には進歩があります。ただし、熟考すると、ある種のトレードオフ(この場合は収束)に対処する必要があります。ここで正しい質問をしているのだろうか。Dのlinalgライブラリへの適切なバインディングは本当にありませんか?
アルス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.