Bagaimana cara melakukan validasi silang untuk PCA untuk menentukan jumlah komponen utama?

13

Saya mencoba untuk menulis fungsi saya sendiri untuk analisis komponen utama, PCA (tentu saja sudah banyak yang ditulis tetapi saya hanya tertarik untuk mengimplementasikan hal-hal sendiri). Masalah utama yang saya temui adalah langkah validasi silang dan menghitung prediksi jumlah kuadrat (PRESS). Tidak masalah validasi silang mana yang saya gunakan, itu pertanyaan utama tentang teori di balik, tetapi pertimbangkan validasi silang keluar-keluar (LOOCV). Dari teori saya menemukan bahwa untuk melakukan LOOCV Anda perlu:

  1. hapus suatu objek
  2. skala sisanya
  3. melakukan PCA dengan sejumlah komponen
  4. skala objek yang dihapus sesuai dengan parameter yang diperoleh pada (2)
  5. memprediksi objek sesuai dengan model PCA
  6. menghitung PRESS untuk objek ini
  7. lakukan kembali algoritma yang sama ke objek lain
  8. jumlah semua nilai PRESS
  9. keuntungan

Karena saya sangat baru di bidang ini, untuk memastikan bahwa saya benar, saya membandingkan hasilnya dengan output dari beberapa perangkat lunak yang saya miliki (juga untuk menulis beberapa kode saya mengikuti petunjuk dalam perangkat lunak). Saya mendapatkan hasil yang sama sekali sama dengan menghitung sisa jumlah kuadrat dan , tetapi menghitung PRESS adalah masalah.R2

Bisakah Anda memberi tahu saya jika apa yang saya terapkan dalam langkah validasi silang benar atau tidak:

case 'loocv'

% # n - number of objects
% # p - number of variables
% # vComponents - the number of components used in CV
dataSets = divideData(n,n); 
         % # it is just a variable responsible for creating datasets for CV 
         % #  (for LOOCV datasets will be equal to [1, 2, 3, ... , n]);'
tempPRESS = zeros(n,vComponents);

for j = 1:n
  Xmodel1 = X; % # X - n x p original matrix
  Xmodel1(dataSets{j},:) = []; % # delete the object to be predicted
  [Xmodel1,Xmodel1shift,Xmodel1div] = skScale(Xmodel1, 'Center', vCenter, 
                                              'Scaling', vScaling); 
          % # scale the data and extract the shift and scaling factor
  Xmodel2 = X(dataSets{j},:); % # the object to be predicted
  Xmodel2 = bsxfun(@minus,Xmodel2,Xmodel1shift); % # shift and scale the object
  Xmodel2 = bsxfun(@rdivide,Xmodel2,Xmodel1div);
  [Xscores2,Xloadings2] = myNipals(Xmodel1,0.00000001,vComponents); 
          % # the way to calculate the scores and loadings
                % # Xscores2 - n x vComponents matrix
                % # Xloadings2 - vComponents x p matrix
  for i = 1:vComponents
    tempPRESS(j,i) = sum(sum((Xmodel2* ...
       (eye(p) - transpose(Xloadings2(1:i,:))*Xloadings2(1:i,:))).^2));
  end
end
PRESS = sum(tempPRESS,1);

Dalam perangkat lunak ( PLS_Toolbox ) berfungsi seperti ini:

for i = 1:vComponents
    tempPCA = eye(p) - transpose(Xloadings2(1:i,:))*Xloadings2(1:i,:);
    for kk = 1:p
        tempRepmat(:,kk) = -(1/tempPCA(kk,kk))*tempPCA(:,kk);
          % # this I do not understand
        tempRepmat(kk,kk) = -1; 
          % # here is some normalization that I do not get
    end 
    tempPRESS(j,i) = sum(sum((Xmodel2*tempRepmat).^2)); 
end

Jadi, mereka melakukan beberapa normalisasi tambahan menggunakan tempRepmatvariabel ini : satu-satunya alasan yang saya temukan adalah bahwa mereka menerapkan LOOCV untuk PCA yang kuat. Sayangnya, tim pendukung tidak ingin menjawab pertanyaan saya karena saya hanya memiliki versi demo dari perangkat lunak mereka.

Kirill
sumber
Lebih jauh memeriksa apakah saya memahami potongan normalisasi tambahan: apa peran tempRepmat(kk,kk) = -1garis? Bukankah baris sebelumnya sudah memastikan bahwa itu tempRepmat(kk,kk)sama dengan -1? Juga, mengapa minus? Kesalahan tetap akan dikuadratkan, jadi apakah saya mengerti benar bahwa jika minus dihapus, tidak ada yang akan berubah?
Amoeba berkata Reinstate Monica
Saya telah memeriksa di masa lalu dan tidak ada yang akan berubah. Itu benar. Saya hanya menemukan beberapa persamaan dengan implementasi PCA yang kuat karena setiap nilai PRESS yang dihitung dalam implementasi tersebut (sebelum menyimpulkan semuanya) memiliki bobotnya sendiri.
Kirill
Saya mencari kode R yang setara dengan kode MATLAB yang disediakan dalam jawaban dan telah memberikan hadiah.
AIM_BLB
3
@CSA, meminta kode di luar topik di sini (bahkan, mungkin, melalui komentar & hadiah). Anda harus dapat menanyakan hal itu di Stack Overflow : Anda dapat menyalin kode, mengutip sumber dengan tautan di sini, & meminta terjemahan. Saya percaya semua itu ada di topik di sana.
gung - Reinstate Monica

Jawaban:

21

Apa yang Anda lakukan salah: tidak masuk akal untuk menghitung PRESS untuk PCA seperti itu! Secara khusus, masalahnya terletak pada langkah Anda # 5.


Pendekatan naif terhadap PRESS untuk PCA

Biarkan set data terdiri dari titik dalam ruang d- dimensional: x ( i )R d ,ndx(i)Rd,i=1nx(i)X(i)kU(i) i P R E S S ? = n i = 1x ( i ) - U ( -x(i)x^(i)2=x(i)U(i)[U(i)]x(i)2i

PRESS=?i=1nx(i)U(i)[U(i)]x(i)2.

Untuk kesederhanaan, saya mengabaikan masalah pemusatan dan penskalaan di sini.

Pendekatan naif itu salah

Masalah di atas adalah bahwa kita menggunakan untuk menghitung prediksi , dan itu adalah Hal yang Sangat Buruk.x(i)x^(i)

Perhatikan perbedaan krusial pada kasus regresi, di mana rumus untuk kesalahan rekonstruksi pada dasarnya sama , tetapi prediksi dihitung menggunakan variabel prediktor dan tidak menggunakan . Ini tidak mungkin di PCA, karena di PCA tidak ada variabel dependen dan independen: semua variabel diperlakukan bersama.y(i)y^(i)2y^(i)y(i)

Dalam prakteknya itu berarti PRESS seperti yang dihitung di atas dapat berkurang dengan meningkatnya jumlah komponen dan tidak pernah mencapai minimum. Yang akan membuat orang berpikir bahwa semua komponen adalah signifikan. Atau mungkin dalam beberapa kasus memang mencapai minimum, tetapi masih cenderung overfit dan melebih-lebihkan dimensi optimal.kd

Pendekatan yang benar

Ada beberapa pendekatan yang mungkin, lihat Bro et al. (2008) Validasi silang model komponen: pandangan kritis pada metode saat ini untuk tinjauan umum dan perbandingan. Satu pendekatan adalah meninggalkan satu dimensi dari satu titik data pada satu waktu (yaitu bukannya ), sehingga data pelatihan menjadi matriks dengan satu nilai yang hilang , dan kemudian untuk memprediksi ("menyalahkan") nilai yang hilang ini dengan PCA. (Seseorang tentu saja dapat secara acak menahan beberapa fraksi elemen matriks yang lebih besar, misalnya 10%). Masalahnya adalah bahwa komputasi PCA dengan nilai-nilai yang hilang dapat komputasi sangat lambat (bergantung pada algoritma EM), tetapi perlu diulang berkali-kali di sini. Pembaruan: lihat http://alexhwilliams.info/itsneuronalblog/2018/02/26/crossval/xj(i)x(i) untuk diskusi yang bagus dan implementasi Python (PCA dengan nilai yang hilang diimplementasikan melalui kuadrat terkecil bergantian).

Suatu pendekatan yang saya temukan jauh lebih praktis adalah dengan mengabaikan satu titik data pada suatu waktu, menghitung PCA pada data pelatihan (persis seperti di atas), tetapi kemudian untuk mengulang dimensi , tinggalkan satu per satu dan hitung kesalahan rekonstruksi menggunakan sisanya. Ini bisa sangat membingungkan pada awalnya dan formula cenderung menjadi sangat berantakan, tetapi implementasi agak mudah. Biarkan saya memberikan formula (agak menakutkan), dan kemudian jelaskan secara singkat:x(i)x(i)

PRESSPCA=i=1nj=1d|xj(i)[U(i)[Uj(i)]+xj(i)]j|2.

Pertimbangkan lingkaran dalam di sini. Kami meninggalkan satu poin dan menghitung komponen utama pada data pelatihan, . Sekarang kita menyimpan setiap nilai sebagai tes dan menggunakan dimensi yang tersisa untuk melakukan prediksi . Prediksi adalah koordinat ke- dari "proyeksi" (dalam arti kuadrat terkecil) dari ke subruang yang direntang oleh . Untuk menghitungnya, cari titik di ruang PC yang paling dekat denganx(i)kU(i)xj(i)xj(i)Rd1x^j(i)jxj(i)U(i)z^Rkxj(i) dengan menghitung mana adalah dengan baris ke- ditendang keluar, dan singkatan dari pseudoinverse. Sekarang petakan kembali ke ruang aslinya: dan mengambil koordinat -nya . z^=[Uj(i)]+xj(i)RkUj(i)U(i)j[]+z^U(i)[Uj(i)]+xj(i)j[]j

Suatu pendekatan terhadap pendekatan yang benar

Saya tidak begitu mengerti normalisasi tambahan yang digunakan dalam PLS_Toolbox, tapi di sini ada satu pendekatan yang mengarah ke arah yang sama.

Ada cara lain untuk memetakan ke ruang komponen utama: , yaitu hanya mengambil transpos alih-alih pseudo-invers. Dengan kata lain, dimensi yang ditinggalkan untuk pengujian tidak dihitung sama sekali, dan bobot yang sesuai juga ditendang keluar. Saya pikir ini harus kurang akurat, tetapi mungkin sering dapat diterima. Hal yang baik adalah bahwa rumus yang dihasilkan sekarang dapat di-vektor sebagai berikut (saya hilangkan perhitungannya):xj(i)z^approx=[Uj(i)]xj(i)

PRESSPCA,approx=i=1nj=1d|xj(i)[U(i)[Uj(i)]xj(i)]j|2=i=1n(IUU+diag{UU})x(i)2,

di mana saya menulis sebagai untuk kekompakan, dan berarti mengatur semua elemen non-diagonal ke nol. Perhatikan bahwa formula ini persis seperti yang pertama (PRESS naif) dengan sedikit koreksi! Perhatikan juga bahwa koreksi ini hanya bergantung pada diagonal dari , seperti pada kode PLS_Toolbox. Namun, rumusnya masih berbeda dari apa yang tampaknya diterapkan di PLS_Toolbox, dan perbedaan ini saya tidak bisa jelaskan. U d i a g {} U UU(i)Udiag{}UU

Pembaruan (Feb 2018): Di atas saya menyebut satu prosedur "benar" dan yang lain "perkiraan" tetapi saya tidak begitu yakin lagi bahwa ini bermakna. Kedua prosedur masuk akal dan saya pikir tidak ada yang lebih benar. Saya sangat suka bahwa prosedur "perkiraan" memiliki formula yang lebih sederhana. Juga, saya ingat bahwa saya memiliki beberapa dataset di mana prosedur "perkiraan" menghasilkan hasil yang tampak lebih bermakna. Sayangnya, saya tidak ingat detailnya lagi.


Contohnya

Berikut adalah perbandingan metode ini untuk dua dataset terkenal: Iris dataset dan wine wine. Perhatikan bahwa metode naif menghasilkan kurva penurunan monoton, sedangkan dua metode lainnya menghasilkan kurva dengan minimum. Perhatikan lebih lanjut bahwa dalam kasus Iris, metode perkiraan menyarankan 1 PC sebagai angka optimal tetapi metode pseudoinverse menyarankan 2 PC. (Dan melihat sebarang sebaran PCA untuk dataset Iris, tampaknya kedua PC pertama membawa beberapa sinyal.) Dan dalam kasus wine, metode pseudoinverse dengan jelas menunjuk pada 3 PC, sedangkan metode perkiraan tidak dapat memutuskan antara 3 dan 5.

masukkan deskripsi gambar di sini


Kode Matlab untuk melakukan validasi silang dan plot hasilnya

function pca_loocv(X)

%// loop over data points 
for n=1:size(X,1)
    Xtrain = X([1:n-1 n+1:end],:);
    mu = mean(Xtrain);
    Xtrain = bsxfun(@minus, Xtrain, mu);
    [~,~,V] = svd(Xtrain, 'econ');
    Xtest = X(n,:);
    Xtest = bsxfun(@minus, Xtest, mu);

    %// loop over the number of PCs
    for j=1:min(size(V,2),25)
        P = V(:,1:j)*V(:,1:j)';        %//'
        err1 = Xtest * (eye(size(P)) - P);
        err2 = Xtest * (eye(size(P)) - P + diag(diag(P)));
        for k=1:size(Xtest,2)
            proj = Xtest(:,[1:k-1 k+1:end])*pinv(V([1:k-1 k+1:end],1:j))'*V(:,1:j)'; 
            err3(k) = Xtest(k) - proj(k);
        end

        error1(n,j) = sum(err1(:).^2);
        error2(n,j) = sum(err2(:).^2);
        error3(n,j) = sum(err3(:).^2);
    end    
end

error1 = sum(error1);
error2 = sum(error2);
error3 = sum(error3);
%// plotting code
figure
hold on
plot(error1, 'k.--')
plot(error2, 'r.-')
plot(error3, 'b.-')
legend({'Naive method', 'Approximate method', 'Pseudoinverse method'}, ...
    'Location', 'NorthWest')
legend boxoff
set(gca, 'XTick', 1:length(error1))
set(gca, 'YTick', [])
xlabel('Number of PCs')
ylabel('Cross-validation error')
amuba kata Reinstate Monica
sumber
Terima kasih atas jawaban Anda! Saya tahu kertas itu. Dan saya menerapkan validasi silang baris-bijaksana yang dijelaskan di sana (tampaknya persis sesuai dengan kode yang saya berikan). Saya membandingkan dengan perangkat lunak PLS_Toolbox tetapi mereka memiliki satu baris kode di LOOCV yang saya benar-benar tidak mengerti (saya menulis dalam pertanyaan awal).
Kirill
Ya, mereka menyebutnya "lintas-bijaksana lintas-validasi" dan implementasi Anda tampaknya baik-baik saja, tetapi harap dicatat bahwa ini adalah cara yang buruk untuk melakukan lintas-validasi (sebagaimana dinyatakan dan juga ditunjukkan secara empiris di Bro et al.) Dan pada dasarnya Anda harus jangan pernah menggunakannya! Mengenai baris kode yang tidak Anda mengerti - apakah Anda akan memperbarui pertanyaan Anda? Tidak yakin apa yang Anda maksud.
Amuba mengatakan Reinstate Monica
Masalahnya adalah bahwa implementasi ini tampaknya memiliki kemampuan untuk mencapai minimum di CV.
Kirill
PRESS dari sangat dekat dengan LOO% menjelaskan varians - Saya tidak akan mengatakan ini baik atau buruk, tapi itu pasti sesuatu yang perlu diperhatikan. Dan seperti% yang dijelaskan varians akan mendekati 1 ketika model PCA mendekati pangkat kumpulan data, X PRESS ini akan mendekati 0.x^x
cbeleites tidak senang dengan SX
@ Kirill: Terima kasih, potongan kode masuk akal sekarang (mungkin Anda dapat menghapus komentar di atas yang sekarang usang). Saya tidak tahu apa yang seharusnya dilakukan, tetapi jika Anda mengatakan itu membuat kesalahan prediksi yang dihitung mencapai minimum, maka mungkin secara efektif memperkenalkan beberapa penalti untuk lebih besar (jumlah komponen; yaitu variabel dalam kode Anda). Sejujurnya, saya akan skeptis terhadap metode semacam itu (kecuali ada pembenaran teoretis untuk itu), terutama mengingat bahwa ada pendekatan yang lebih baik seperti yang saya jelaskan dalam jawaban saya. ki
Amoeba berkata Reinstate Monica
1

Untuk menambahkan poin yang lebih umum lagi ke jawaban bagus @ amoeba:

Satu perbedaan praktis dan krusial antara model yang diawasi dan yang tidak diawasi adalah bahwa untuk model yang tidak diawasi, Anda perlu berpikir lebih keras tentang apa yang Anda anggap setara dan yang tidak.

Model yang diawasi selalu memiliki hasil akhir mereka dengan cara di mana Anda tidak perlu terlalu peduli tentang ini: dengan definisi dan konstruksi, mengklaim memiliki makna yang sama dengan , sehingga Anda dapat langsung membandingkannya. y yy^y^y

Untuk membangun ukuran kinerja yang berarti, Anda perlu memikirkan jenis kebebasan apa dari model yang tidak berarti untuk aplikasi Anda dan mana yang tidak. Itu akan mengarah pada PRESS pada skor, mungkin (biasanya?) Setelah semacam rotasi / pembalikan seperti Procrustes.

PRESS on x Dugaan saya adalah (Saya tidak punya waktu sekarang untuk mengetahui apa yang dilakukan 2 baris kode mereka - tetapi mungkin Anda bisa melangkahi garis-garis tersebut dan melihatnya?):

Untuk mendapatkan ukuran yang berguna untuk menentukan kompleksitas model yang baik dari ukuran yang memberikan goodness of fit yang biasanya akan meningkat hingga model peringkat penuh tercapai, Anda perlu menghukum model yang terlalu rumit. Yang pada gilirannya berarti bahwa hukuman ini adalah a) krusial dan b) menyesuaikan penalti akan menyesuaikan kompleksitas yang dipilih.


Catatan: Saya hanya ingin menambahkan bahwa saya akan sangat berhati-hati dengan jenis optimisasi kompleksitas model otomatis ini. Dalam pengalaman saya banyak dari algoritma ini hanya menghasilkan pseudo-objektivitas, dan seringkali datang pada biaya bekerja dengan baik hanya untuk tipe data tertentu.

cbeleites tidak senang dengan SX
sumber