Tại sao PCA của dữ liệu bằng phương tiện SVD của dữ liệu?


22

Câu hỏi này là về một cách hiệu quả để tính toán các thành phần chính.

  1. Nhiều văn bản trên PCA tuyến tính ủng hộ việc sử dụng phân tách giá trị số ít của dữ liệu casewise . Nghĩa là, nếu chúng ta có dữ liệu và muốn thay thế các biến ( cột của nó ) bằng các thành phần chính, chúng ta thực hiện SVD: , các giá trị số ít (gốc của các giá trị riêng) chiếm đường chéo chính của , các hàm riêng bên phải là ma trận xoay trực giao của các biến trục thành các thành phần trục, các hàm riêng bên trái giống như , chỉ dành cho các trường hợp. Sau đó chúng ta có thể tính các giá trị thành phần là .X = U S V S V U V C = X V = U SXX=USVSVUVC=XV=US

  2. Một cách khác để thực hiện PCA của các biến là thông qua phân tách ma trận vuông (nghĩa là có thể là tương quan hoặc hiệp phương sai , v.v., giữa các biến). Phân rã có thể là phân rã eigen hoặc phân rã giá trị số ít: với ma trận bán nguyệt dương đối xứng vuông, chúng sẽ cho cùng một kết quả với các giá trị riêng như đường chéo của và như được mô tả trước đó. Giá trị thành phần sẽ là .R R = V L V L V C = X VR=XXR R=VLVLVC=XV

Bây giờ, câu hỏi của tôi: nếu dữ liệu là một ma trận lớn và số trường hợp là (thường là một trường hợp) lớn hơn nhiều so với số lượng biến, thì cách (1) được dự kiến ​​sẽ chậm hơn nhiều so với cách (2) ), bởi vì cách (1) áp dụng một thuật toán khá tốn kém (như SVD) cho một ma trận lớn; nó tính toán và lưu trữ ma trận khổng lồ mà chúng ta thực sự không cần trong trường hợp của chúng ta (PCA của các biến). Nếu vậy, tại sao rất nhiều texbooks dường như ủng hộ hoặc chỉ đề cập đến cách duy nhất (1)? Có lẽ nó hiệu quả và tôi đang thiếu cái gì?UXU


2
Nói chung, chúng tôi chỉ quan tâm đến một vài thành phần chính giải thích hầu hết các phương sai. Có thể làm giảm SVD; ví dụ nếu là chiều nơi sau đó 's chức năng sẽ tính toán chỉ là người đầu tiên trái và phải vectơ số ít theo mặc định. N × p p < < N pXN×pp<<NRsvdp
M. Berk

1
@ M.Berk: tuy nhiên, giống nhau trong cả hai cách tiếp cận: chúng mang lại kết quả tương đương (bằng với thay đổi dấu hiệu). Ngoài ra, ví dụ R chỉ tính toán nếu được yêu cầu. CpC
cbeleites hỗ trợ Monica

Bạn có một tài liệu tham khảo cho cách (1)? Tôi chỉ biết PCA được triển khai thông qua SVD trên ma trận hiệp phương sai (tức là cách 2), vì điều này tránh được một số vấn đề về số và tỷ lệ rõ ràng với kích thước, không phải kích thước tập dữ liệu. Cách (1) Tôi sẽ gọi SVD, không phải PCA. Tôi chỉ thấy nó trong một bối cảnh SVD thuần túy, nơi người ta sẽ không thực hiện phân tách hoàn toàn.
Anony-Mousse

@ Anony-Mousse, Chỉ cần nhắc đến một điều, Joliffe, Principal component analysis, 2nd ed.Thật ra, Joliffe mô tả cả hai cách, nhưng trong chương cốt lõi về PCA, anh ấy nói về cách 1, theo như tôi có thể nhớ.
ttnphns

@ Anony-Mousse, Cách 1 đối với tôi rất quan trọng từ điểm lý thuyết vì nó cho thấy rõ PCA liên quan trực tiếp đến phân tích tương ứng đơn giản như thế nào .
ttnphns

Câu trả lời:


7

Đây là 2ct của tôi về chủ đề này

  • Bài giảng hóa học nơi lần đầu tiên tôi học PCA đã sử dụng giải pháp (2), nhưng nó không được định hướng bằng số và bài giảng về số của tôi chỉ là một giới thiệu và không thảo luận về SVD theo như tôi nhớ.

  • Nếu tôi hiểu Holmes: SVD nhanh cho ma trận quy mô lớn một cách chính xác, ý tưởng của bạn đã được sử dụng để có được một SVD tính toán nhanh của ma trận dài.
    Điều đó có nghĩa là việc triển khai SVD tốt có thể theo bên trong (2) nếu nó gặp ma trận phù hợp (tôi không biết liệu còn những khả năng tốt hơn không). Điều này có nghĩa là để triển khai ở cấp độ cao, tốt hơn là sử dụng SVD (1) và để nó cho BLAS để quan tâm đến việc sử dụng thuật toán nào trong nội bộ.

  • Kiểm tra thực tế nhanh: Svd của OpenBLAS dường như không tạo ra sự khác biệt này, trên ma trận 5e4 x 100, svd (X, nu = 0)mất trung bình 3,5 giây, trong khi svd (crossprod (X), nu = 0)mất 54 ms (được gọi từ R với microbenchmark).
    Tất nhiên, bình phương của các giá trị riêng là nhanh và kết quả của cả hai cuộc gọi là bằng nhau.

    timing  <- microbenchmark (svd (X, nu = 0), svd (crossprod (X), nu = 0), times = 10)
    timing
    # Unit: milliseconds
    #                      expr        min         lq    median         uq        max neval
    #            svd(X, nu = 0) 3383.77710 3422.68455 3507.2597 3542.91083 3724.24130    10
    # svd(crossprod(X), nu = 0)   48.49297   50.16464   53.6881   56.28776   59.21218    10
    

cập nhật: Hãy xem Wu, W.; Massart, D. & de Jong, S.: Các thuật toán PCA nhân cho dữ liệu rộng. Phần I: Lý thuyết và thuật toán, Hệ thống phòng thí nghiệm hóa học và thông minh, 36, 165 - 172 (1997). DOI: http://dx.doi.org/10.1016/S0169-7439(97)00010-5

Bài viết này thảo luận về các đặc tính số và tính toán của 4 thuật toán khác nhau cho PCA: SVD, phân tách eigen (EVD), NIPALS và POWER.

Chúng có liên quan như sau:

computes on      extract all PCs at once       sequential extraction    
X                SVD                           NIPALS    
X'X              EVD                           POWER

Bối cảnh của bài viết rộng và chúng hoạt động trên (kernel PCA) - đây chỉ là tình huống ngược lại như bạn hỏi. Vì vậy, để trả lời câu hỏi của bạn về hành vi ma trận dài, bạn cần trao đổi ý nghĩa của "hạt nhân" và "cổ điển".X(30×500)XX

so sánh hiệu suất

Không có gì đáng ngạc nhiên, EVD và SVD thay đổi vị trí tùy thuộc vào việc sử dụng thuật toán cổ điển hay kernel. Trong bối cảnh của câu hỏi này, điều này có nghĩa là cái này hay cái kia có thể tốt hơn tùy thuộc vào hình dạng của ma trận.

Nhưng từ cuộc thảo luận của họ về SVD "cổ điển" và EVD, rõ ràng việc phân tách là một cách rất thông thường để tính PCA. Tuy nhiên, họ không chỉ định thuật toán SVD nào được sử dụng ngoài việc họ sử dụng hàm Matlab .XXsvd ()


    > sessionInfo ()
    R version 3.0.2 (2013-09-25)
    Platform: x86_64-pc-linux-gnu (64-bit)

    locale:
     [1] LC_CTYPE=de_DE.UTF-8       LC_NUMERIC=C               LC_TIME=de_DE.UTF-8        LC_COLLATE=de_DE.UTF-8     LC_MONETARY=de_DE.UTF-8   
     [6] LC_MESSAGES=de_DE.UTF-8    LC_PAPER=de_DE.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
    [11] LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C       

    attached base packages:
    [1] stats     graphics  grDevices utils     datasets  methods   base     

    other attached packages:
    [1] microbenchmark_1.3-0

loaded via a namespace (and not attached):
[1] tools_3.0.2

$ dpkg --list libopenblas*
[...]
ii  libopenblas-base              0.1alpha2.2-3                 Optimized BLAS (linear algebra) library based on GotoBLAS2
ii  libopenblas-dev               0.1alpha2.2-3                 Optimized BLAS (linear algebra) library based on GotoBLAS2

Vì vậy, thử nghiệm của bạn (3,5 giây so với 54 ms) hỗ trợ cho dòng của tôi rằng "cách 1" chậm hơn đáng kể. Đúng?
ttnphns

1
@ttnphns: vâng. Nhưng vì svd được cung cấp bởi BLAS có thể khác với BLAS khác. Tôi đã mong đợi rằng một BLAS được tối ưu hóa tốt sẽ làm một cái gì đó như thế này. Tuy nhiên, dường như đó không phải là trường hợp của OpenBLAS. Tôi quá lười để kiểm tra các BLAS khác, nhưng có lẽ một vài người có thể kiểm tra các BLAS khác của họ để chúng tôi tìm ra cái nào được tối ưu hóa cho trường hợp này và cái nào không. (Tôi đã gửi email cho nhà phát triển OpenBLAS và gửi cho anh ấy một liên kết đến câu hỏi này, vì vậy có lẽ anh ta có thể thêm một số thông tin, ví dụ như lý do không chuyển thuật toán sang svd (X'X)ma trận dài.)
cbeleites hỗ trợ Monica

Một số điểm cần làm rõ (với tôi). Các "phương thức kernel" có thể được tóm tắt là "hoạt động trên thay vì khi " không? nếu vậy thì nó khá tầm thường. Tôi không biết POWER nhưng tôi biết NIPALS, tính toán các hàm riêng của bằng cách lặp(hội tụ của anh ta với eigenvector thứ 1 , sau đó bạn phải cập nhật để tính toán lần thứ hai, v.v.). Có hai cách để thực hiện NIPALS, (1) bạn có thể tính toán trước hoặc (2) bạn có thể thực hiện sản phẩm dưới dạng , cách nào được sử dụng ở đây? Tôi đoán (1) được sử dụng, có thể không công bằng.XXn<pXXun+1=XXun/||XXun||v1XXXX×(Xun)

@Elvis: a) Có nhiều phương thức kernel hơn là chỉ tính toán trên , xem ví dụ: stats.stackexchange.com/questions/2499/ . Sự tương đương là không đáng kể đối với PCA (không quan trọng bạn bắt đầu bằng cách lấy các vectơ số phải hay trái) nhưng không phải cho các phương pháp khác. b) "cách làm NIPALS" dựa trên cùng một nguyên tắc chung. Thuật toán nào được sử dụng cho SVD phụ thuộc vào BLAS của bạn và thực sự tôi đoán là NIPALS không liên quan ở đây. Lưu ý rằng thời gian của tôi bao gồm tính toán của sản phẩm chéo. XXT
cbeleites hỗ trợ Monica

Tôi đã nói về cập nhật của bạn, nơi Nipals có liên quan. Tôi xác nhận Nipals không liên quan đến SVD của Lapack. Về thử nghiệm điểm chuẩn của bạn, một cái gì đó giống như microbenchmark(X <- matrix(rnorm(5e6), ncol=100), Y <- t(X), svd(X), svd(Y), control=list(order="inorder"), times = 5)có thể thú vị là tốt.
Elvis

18

SVD chậm hơn nhưng thường được coi là phương pháp ưa thích vì độ chính xác số cao hơn.

Như bạn nêu trong câu hỏi, phân tích thành phần chính (PCA) có thể được thực hiện bằng SVD của ma trận dữ liệu trung tâm ( xem chủ đề Q & A này để biết thêm chi tiết ) hoặc bằng cách phân tách riêng của ma trận hiệp phương sai (hoặc, thay vào đó, nếu , xem tại đây để biết thêm chi tiết ).XXXnp1n1XXXXnp

Đây là những gì được viết trong trợ giúppca() chức năng của MATLAB :

Thuật toán thành phần chính pcasử dụng để thực hiện phân tích thành phần chính [...]:

'svd' - Mặc định. Phân rã giá trị số ít (SVD) của X.

'Eig' - Phân tách Eigenvalue (EIG) của ma trận hiệp phương sai. Thuật toán EIG nhanh hơn SVD khi số lượng quan sát, , vượt quá số lượng biến, , nhưng kém chính xác hơn vì số điều kiện của hiệp phương sai là bình phương của số điều kiện của X.pnp

Câu cuối cùng nêu bật sự đánh đổi chính xác tốc độ quan trọng đang diễn ra ở đây.

Bạn có quyền quan sát rằng sự xuất tinh của ma trận hiệp phương sai thường nhanh hơn SVD của ma trận dữ liệu. Dưới đây là một điểm chuẩn ngắn trong Matlab với ma trận dữ liệu ngẫu nhiên :1000×100

X = randn([1000 100]);

tic; svd(X); toc         %// Elapsed time is 0.004075 seconds.
tic; svd(X'); toc        %// Elapsed time is 0.011194 seconds.
tic; eig(X'*X); toc      %// Elapsed time is 0.001620 seconds.
tic; eig(X*X'); toc;     %// Elapsed time is 0.126723 seconds.

Cách nhanh nhất trong trường hợp này là thông qua ma trận hiệp phương sai (hàng thứ ba). Tất nhiên, nếu (thay vì ngược lại) thì đó sẽ là cách chậm nhất, nhưng trong trường hợp đó, sử dụng ma trận Gram (hàng thứ tư) sẽ là cách nhanh nhất thay thế. Bản thân SVD của ma trận dữ liệu sẽ chậm hơn.X XnpXX

Tuy nhiên, nó sẽ chính xác hơn vì nhân với chính nó có thể dẫn đến mất độ chính xác bằng số. Dưới đây là một ví dụ, được điều chỉnh từ câu trả lời của @ JM cho Tại sao SVD trên được ưu tiên hơn cho việc xuất tinh của trong PCA trên Math.SE.X X X XXXX

Xem xét ma trận dữ liệu đôi khi được gọi là ma trận Läuchli (và chúng ta hãy bỏ qua việc định tâm cho ví dụ này). Các giá trị số đơn bình phương của nó là , và . Lấy , chúng ta có thể sử dụng SVD và EIG để tính các giá trị này:3 + ε 2 ε 2 ε 2 ε = 10 - 5

X=(111ϵ000ϵ000ϵ),
3+ϵ2ϵ2ϵ2ϵ=105
eps = 1e-5;
X = [1 1 1; eye(3)*eps];
display(['Squared sing. values of X: ' num2str(sort(svd(X),'descend').^2')])
display(['Eigenvalues of X''*X:       ' num2str(sort(eig(X'*X),'descend')')])

thu được kết quả giống hệt nhau:

Squared sing. values of X: 3       1e-10       1e-10
Eigenvalues of X'*X:       3       1e-10       1e-10

ϵ=1010

Squared sing. values of X: 3       1e-20       1e-20
Eigenvalues of X'*X:       3           0 -3.3307e-16

XX

Tôi nên nói thêm rằng người ta thường rất vui khi bỏ qua sự mất chính xác [nhỏ bé] này và sử dụng phương pháp nhanh hơn.


1
XTX

Cảm ơn câu trả lời và xem xét kỹ lưỡng về ưu và nhược điểm.
ttnphns

amip, có thể là bạn tìm thấy thời gian để đưa ra một ví dụ cụ thể trong đó sự ổn định số phải chịu theo eig()cách tiếp cận? (Độc giả sẽ được hưởng lợi: có một điểm đánh đổi giữa tốc độ và sự ổn định. Làm thế nào một người có thể quyết định trong một tình huống thực tế cụ thể?)
ttnphns

@ttnphns Tôi viết lại toàn bộ câu trả lời, cung cấp một ví dụ cụ thể. Hãy xem.
amip nói phục hồi Monica

1
@amoeba, cảm ơn bạn rất nhiều vì đã trở lại và đưa ra một ví dụ! Tôi đã thử cả hai ví dụ epsilon trong SPSS và nhận được kết quả như của bạn ngoại trừ dòng cuối cùng: thay vì 3 0 -3.3307e-16eigen trong spss trả lại cho tôi 3 0 0. Có vẻ như hàm này có một số giá trị dung sai cố định được xây dựng và cố định mà không có giá trị nào. Trong ví dụ này, hàm xuất hiện như thể hack nút không ổn định số bằng cách bỏ cả hai giá trị riêng nhỏ, "0" và "-16".
ttnphns
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.