สุดยอดอัลกอริธึม PCA สำหรับฟีเจอร์มากมาย (> 10K)?


54

ก่อนหน้านี้ฉันเคยถามเรื่องนี้ใน StackOverflow แต่ดูเหมือนว่าอาจเหมาะสมกว่าที่นี่เนื่องจากไม่ได้รับคำตอบใด ๆ เกี่ยวกับ SO มันเป็นจุดตัดระหว่างสถิติกับการเขียนโปรแกรม

ฉันต้องเขียนโค้ดบางอย่างเพื่อทำ PCA (การวิเคราะห์ส่วนประกอบหลัก) ฉันเรียกดูผ่านอัลกอริทึมที่รู้จักกันดีและใช้สิ่งนี้ซึ่งเท่าที่ฉันสามารถบอกได้เท่ากับอัลกอริทึม NIPALS มันใช้งานได้ดีสำหรับการค้นหาส่วนประกอบหลัก 2-3 ชิ้นแรก แต่ดูเหมือนจะช้ามากที่จะรวมกัน (ตามลำดับการทำซ้ำหลายร้อยถึงหลายพัน) นี่คือรายละเอียดของสิ่งที่ฉันต้องการ:

  1. อัลกอริทึมจะต้องมีประสิทธิภาพเมื่อจัดการกับคุณสมบัติจำนวนมาก (สั่ง 10,000 ถึง 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
robin girard

คำตอบ:


27

ฉันได้ใช้ SVD แบบสุ่มตามที่กำหนดใน "Halko, N. , Martinsson, PG, Shkolnisky, Y. , & Tygert, M. (2010) อัลกอริทึมสำหรับการวิเคราะห์องค์ประกอบหลักของชุดข้อมูลขนาดใหญ่ Arxiv preprint arXiv: 1007.5510, 0526 สืบค้น 1 เมษายน 2011, จากhttp://arxiv.org/abs/1007.5510 . " หากคุณต้องการรับ SVD ที่ถูกตัดทอนมันจะทำงานได้เร็วกว่าการเปลี่ยนแปลง svd ใน MATLAB คุณสามารถรับได้ที่นี่:

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

อย่างที่คุณเห็นค่าต่ำkมันเร็วกว่าการใช้ Matlab SVD มากกว่า 10 เท่า โดยวิธีการที่คุณอาจต้องฟังก์ชั่นง่าย ๆ ต่อไปนี้สำหรับฟังก์ชั่นการทดสอบ

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

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

ฉันไม่ได้เพิ่มวิธี PCA เพราะตรงไปตรงมาเพื่อใช้งานโดยใช้ SVD คุณสามารถตรวจสอบลิงค์นี้เพื่อดูความสัมพันธ์ของพวกเขา


12

คุณสามารถลองใช้สองสามตัวเลือก

1- เมทริกซ์การสลายตัวที่ถูกลงโทษ คุณใช้ข้อ จำกัด การลงโทษบางอย่างกับคุณและ v เพื่อให้ได้บางเบาบาง อัลกอริทึมด่วนที่ใช้กับข้อมูลจีโนม

ดู Whitten Tibshirani พวกเขายังมี R-pkg "การสลายตัวของเมทริกซ์ที่ถูกลงโทษพร้อมกับการประยุกต์ใช้กับองค์ประกอบหลักที่กระจัดกระจายและการวิเคราะห์สหสัมพันธ์แบบแคนนอน"

2- สุ่ม SVD เนื่องจาก SVD เป็นอัลกอริธึมต้นแบบค้นหาการประมาณค่าที่รวดเร็วมากอาจเป็นที่ต้องการโดยเฉพาะอย่างยิ่งสำหรับการวิเคราะห์เชิงสำรวจ ด้วยการใช้ SVD แบบสุ่มคุณสามารถทำ PCA บนชุดข้อมูลขนาดใหญ่

ดู Martinsson, Rokhlin และ Tygert "อัลกอริทึมแบบสุ่มสำหรับการสลายตัวของเมทริกซ์" Tygert มีรหัสสำหรับการนำ PCA ไปใช้อย่างรวดเร็ว

ด้านล่างเป็นการใช้งาน SVD แบบสุ่มใน R อย่างง่าย

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 สำหรับการแยกเมทริกซ์ที่ถูกลงโทษ แพ็คเกจนั้นน่าทึ่งมาก ฉันอาจจะพูดถึงว่ามันสะกดว่า "Witten" แต่ในกรณีที่ผู้คนมีปัญหาในการค้นหาการอ้างอิง สุดท้าย OP กล่าวว่าพวกเขาไม่ต้องการอะไรที่เขียนใน R แต่ส่วนใหญ่แพคเกจ SVD ขนาดใหญ่ออกมีจะมีแบ็กเอนด์ C, C ++ หรือ Fortran สำหรับความเร็ว
David J. Harris

4

มันเสียงเหมือนบางทีคุณอาจต้องการที่จะใช้Lanczos อัลกอริทึม หากล้มเหลวคุณอาจต้องการปรึกษาGolub & Van Loan ฉันเคยเขียนอัลกอริทึม SVD (ใน SML ของทุกภาษา) จากข้อความของพวกเขาและมันทำงานได้ดีพอสมควร


3

ฉันขอแนะนำให้ลองใช้เคอร์เนล PCAซึ่งมีเวลา / พื้นที่ซับซ้อนขึ้นอยู่กับจำนวนของตัวอย่าง (N) มากกว่าจำนวนฟีเจอร์ (P) ซึ่งฉันคิดว่าจะเหมาะสมกว่าในการตั้งค่าของคุณ (P >> N) Kernel PCA โดยทั่วไปทำงานร่วมกับเคอร์เนล NxN (เมทริกซ์ของความคล้ายคลึงกันระหว่างจุดข้อมูล) แทนที่จะเป็นเมทริกซ์ความแปรปรวนร่วม PxP ซึ่งยากที่จะจัดการกับ P ขนาดใหญ่สิ่งที่ดีอีกอย่างเกี่ยวกับเคอร์เนล PCA คือมันสามารถเรียนรู้การคาดการณ์ที่ไม่ใช่เชิงเส้น เช่นกันถ้าคุณใช้กับเคอร์เนลที่เหมาะสม ดูกระดาษนี้ PCA


2

ฉันดูเหมือนจะจำได้ว่ามันเป็นไปได้ที่จะดำเนินการ PCA โดยการคำนวณการสลายตัวของ eigen ของ X ^ TX มากกว่า XX ^ T แล้วเปลี่ยนเป็นพีซี อย่างไรก็ตามฉันไม่สามารถจำรายละเอียดได้ แต่มันอยู่ในหนังสือของ Jolliffe (ยอดเยี่ยม) และฉันจะดูมันเมื่อฉันไปทำงาน ฉันจะถอดความประจำพีชคณิตเชิงเส้นจากเช่นวิธีเชิงตัวเลขใน C แทนที่จะใช้อัลกอริทึมอื่น ๆ


5
ความเศร้าโศกที่ดี ... การสร้างเมทริกซ์ความแปรปรวนร่วมนั้นไม่ใช่วิธีที่ดีที่สุดสำหรับ SVD ฉันแสดงตัวอย่างของเหตุผลที่ชัดเจนขึ้นรูปเมทริกซ์ความแปรปรวนไม่ได้เป็นความคิดที่ดีที่ math.SE นี้: math.stackexchange.com/questions/3869/3871#3871
JM ไม่ใช่นักสถิติ

1

นอกจากนี้ยังมีวิธีบูตสแตรปโดย Fisher et alออกแบบมาสำหรับตัวอย่างที่มีมิติสูงหลายร้อยตัวอย่าง

แนวคิดหลักของวิธีการนี้ถูกกำหนดเป็น "resampling คือการแปลงในระดับต่ำ" ดังนั้นหากคุณมีตัวอย่างมิติสูงจำนวนน้อย (หลายร้อย) ดังนั้นคุณจะไม่สามารถรับส่วนประกอบหลักได้มากกว่าจำนวนตัวอย่าง ดังนั้นจึงเหมาะสมที่จะพิจารณาตัวอย่างว่าเป็นพื้นฐานที่ใช้ในการจัดสรรข้อมูลในพื้นที่ย่อยเชิงเส้นที่ครอบคลุมโดยเวกเตอร์เหล่านี้และคำนวณ PCA ภายในพื้นที่ย่อยขนาดเล็กนี้ พวกเขายังให้รายละเอียดเพิ่มเติมเกี่ยวกับวิธีจัดการกับกรณีเมื่อตัวอย่างบางอย่างอาจถูกเก็บไว้ในหน่วยความจำ


0

ดูกระดาษแซม Roweis' EM อัลกอริทึมสำหรับ PCA และ SPCA


อัลกอริทึมของ Wikipedia อ้างถึงสิ่งนี้และเทียบเท่ากับสิ่งนี้สำหรับกรณีของการค้นหาองค์ประกอบหลักทีละรายการ
dsimcha

ตกลงฉันเห็นลิงค์ทันที นี่เป็นวิธีการที่ค่อนข้างง่ายและเช่นเดียวกับที่วิกิพีเดียกล่าวถึงมีความก้าวหน้าตามแนวคิดพื้นฐานนี้ ในการไตร่ตรองคุณจะต้องจัดการกับการแลกเปลี่ยน (การบรรจบกันในกรณีนี้) ฉันสงสัยว่าคุณกำลังถามคำถามที่ถูกต้องที่นี่หรือไม่ จริง ๆ แล้วไม่มีการผูกที่ดีกับไลบรารี linalg สำหรับ D
ARS
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.