Çok sayıda özellik (> 10K) için en iyi PCA algoritması?


54

Bunu daha önce StackOverflow'ta sormuştum, ancak SO'da yanıt alamadığı için burada daha uygun olabilir gibi görünüyor. İstatistik ve programlama arasındaki kesişme noktasında.

PCA (Asıl Bileşen Analizi) yapmak için bazı kodlar yazmam gerekiyor. Ben tanınmış algoritmalar aracılığıyla göz ve uyguladık bu bir bildiğim kadarıyla söyleyebilirim NIPALS algoritması eşdeğerdir. İlk 2-3 ana bileşeni bulmak için iyi çalışır, ancak daha sonra birleşmek için çok yavaş gözükür (yüzlerce ila binlerce yineleme sırasına göre). İhtiyacım olanın detayları:

  1. Algoritma, çok sayıda özellik (10.000 - 20.000 arası sipariş) ve birkaç yüzlük sipariş üzerine numune boyutları ile çalışırken etkin olmalıdır.

  2. Hedef dili henüz D olan, çünkü bir tane olmayan düzgün bir cebir / matris kütüphanesi olmadan makul şekilde uygulanabilir olması gerekir, ve olsa bile, söz konusu projeye bağımlılık olarak eklememeyi tercih ederim. .

Bir yan not olarak, aynı veri setinde R, tüm ana bileşenleri çok hızlı buluyor gibi görünmektedir, ancak kendim kodlamak istediğim bir şey değil, tekil değer ayrıştırması kullanmaktadır.


2
Genel SVD algoritmaları bir sürü var. Bakınız en.wikipedia.org/wiki/… . Bunlardan birini kullanamaz veya uyarlayamaz mısın? Ayrıca, R açık kaynaklıdır ve bir GPL lisansı altındadır, öyleyse neden işi yapıyorsa algoritmasını ödünç almıyorsunuz?
Rob Hyndman

@Rob: Pratik olarak doğrusal bir cebir kütüphanesi yazmaktan kaçınmak istiyorum ve ayrıca GPL'nin kopukluğundan da kaçınmak istiyorum. Ayrıca, daha önce R kaynak kodunun bitlerine ve parçalarına baktım ve bu genellikle çok okunaklı değil.
dsimcha

4
Bir şey mi eksik? > 10K özellikleriniz var ancak <1K örnek var mı? Bu, son 9K bileşenlerinin keyfi olduğu anlamına gelir. İlk bileşenlerin hepsini 1K ister misiniz?
shabbychef

2
Her halükarda, çok sayıda sayısal lineer cebir araştırması sayesinde SVD'yi uygulamak zorunda kalmazsınız, matrisinizin ne kadar büyük / küçük, seyrek / yoğun olduğuna bağlı olarak seçebileceğiniz birçok yöntem vardır. sadece tekil değerleri veya tam tekil değerler setini ve sol / sağ tekil vektörleri istersiniz. IMHO'yu anlamak için algoritmalar çok zor değil.
JM, istatistikçi değil

Neden PCA yapmak istediğinizi söyleyebilir misiniz?
Robin Girard

Yanıtlar:


27

"Halko, N., Martinsson, PG, Shkolnisky, Y. ve Tygert, M. (2010) 'da verilen Randomize SVD'yi uyguladım. Büyük veri setlerinin temel bileşen analizi için bir algoritma. Arxiv preprint arXiv: 1007.5510, 0526. 1 Nisan 2011 tarihinde http://arxiv.org/abs/1007.5510 adresinden alındı . " Eğer SVD'yi kesmek istiyorsanız, MATLAB'deki svd çeşitlerinden çok daha hızlı çalışır. Buradan alabilirsiniz:

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

Test etmek için, aynı klasörde bir resim oluşturun (aynı büyük matris gibi, matrisi kendiniz de oluşturabilirsiniz)

% 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)')

Hızlı svd

Masaüstünde 635 * 483 boyutunda bir görüntü için çalıştırdığımda,

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

Gördüğünüz gibi, düşük değerler için k, Matlab SVD kullanmaktan 10 kat daha hızlıdır. Bu arada, test fonksiyonu için aşağıdaki basit fonksiyona ihtiyacınız olabilir:

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

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

PCA yöntemini eklemedim, çünkü SVD kullanarak gerçekleştirilmesi çok kolay. İlişkilerini görmek için bu bağlantıyı kontrol edebilirsiniz .


12

birkaç seçenek kullanmayı deneyebilirsin.

1- Ceza Matris Ayrıştırma . Biraz beklemek için u ve v'lerde bazı ceza kısıtlamaları uygularsınız. Genomik verilerinde kullanılan hızlı algoritma

Whitten Tibshirani'ye bakınız. Ayrıca bir R-pkg var. "Temel bileşenleri ve kanonik korelasyon analizini seyrek yapmak için uygulamalarla cezalandırılmış bir matris ayrışması."

2- Randomize SVD . SVD bir ana algoritma olduğundan, özellikle keşif analizi için çok hızlı bir yaklaşım istenebilir. Randomize SVD kullanarak PCA'yı büyük veri kümelerinde yapabilirsiniz.

Bkz. Martinsson, Rokhlin ve Tygert, "Matrislerin ayrışması için rastgele bir algoritma". Tygert, PCA'nın çok hızlı bir şekilde uygulanması için bir koda sahiptir.

Aşağıda, R'deki randomize SVD'nin basit bir uygulaması verilmiştir.

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)
}

Cezalandırılmış matris ayrıştırma için +1. Bu paket oldukça şaşırtıcı. Muhtemelen, insanların alıntı yapmakta zorlanmaları durumunda, "Witten" yazıldığından bahsetmeliyim. Son olarak, OP R'de yazılı hiçbir şey istemediklerini, ancak temelde herhangi bir büyük SVD paketinin hız için C, C ++ veya Fortran arka ucuna sahip olacağını söyledi.
David J. Harris,


3

Ayarınızda daha uygun olacağını düşündüğüm özelliklerin sayısı (P) yerine, örneklerin sayısına (N) bağlı bir zaman / mekan karmaşıklığına sahip olan çekirdek PCA'yı denemenizi öneririm (P >> N)). Çekirdek PCA temel olarak, büyük P için başa çıkması zor olabilecek PxP kovaryans matrisi yerine NxN çekirdek matrisi (veri noktaları arasındaki benzerlik matrisi) ile çalışır. Ayrıca uygun bir çekirdekle kullanıyorsanız. Çekirdek PCA'da bu makaleye bakın .


2

PCA'nın X ^ TX'in öz ayrışımını hesaplayarak XX ^ T yerine PCA'yı gerçekleştirmenin mümkün olduğunu hatırlıyor gibiyim ve daha sonra PC'leri almak için dönüştüm. Ancak ayrıntıları elimde hatırlayamıyorum, ancak Jolliffe'nin (mükemmel) kitabında yer alıyor ve işteyken bakacağım. Doğrusal cebir rutinlerini başka bir algoritma kullanmak yerine, örneğin C'deki Sayısal Yöntemlerden çeviririm.


5
İyi keder ... kovaryans matrisini oluşturmak SVD için asla en iyi yol değildir. Açıkça kovaryans matrisi oluşturma matematiğinde iyi bir fikir olmadığına bir örnek gösterdim.SE: math.stackexchange.com/questions/3869/3871#3871 .
JM,

1

Ayrıca, birkaç yüz yüksek boyut örneği için tasarlanmış Fisher ve ark.nın önyükleme yöntemi de vardır .

Yöntemin ana fikri "yeniden örnekleme düşük boyutlu bir dönüşümdür" şeklinde formüle edilmiştir. Bu nedenle, eğer küçük (birkaç yüz) adet yüksek boyutlu örneğiniz varsa, örnek sayınızdan daha fazla temel bileşen elde edemezsiniz. Bu nedenle örnekleri bir temel olarak kabul etmek, verileri bu vektörlerin kapsadığı doğrusal alt alana yansıtmak ve bu daha küçük alt alandaki PCA'yı hesaplamak mantıklıdır. Ayrıca, tüm örnekler bellekte saklanamadığında durumla nasıl başa çıkılacağı konusunda daha fazla ayrıntı sağlarlar.


0

Sam Roweis'in makalesi, PCA ve SPCA için EM Algoritmaları .


Vikipedi algoritması bunu gösterir ve aynı anda bir ana bileşen bulmak için buna eşdeğerdir.
dsimcha

Tamam, şimdi bağlantıyı görüyorum. Bu oldukça basit bir yaklaşım ve Wikipedia'nın da belirttiği gibi, bu temel fikirde ilerlemeler var. Yine de, yansıma üzerine bir tür takasla uğraşmanız gerekecek (bu durumda yakınsama). Burada doğru soruyu sorup sormadığını merak ediyorum. D için linalg kütüphanelerine gerçekten iyi bir bağlanma yok mu?
ars
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.