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=1…nx(i)X(−i)kU(−i) i P R E S S ? = n ∑ i = 1 ‖ x ( i ) - U ( -∥∥x( i )- x^( i )∥∥2= ∥∥x( i )- U( - i )[ U( - i )]⊤x( i )∥∥2saya
P R E S S =?∑i = 1n∥∥x( 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/x( i )jx( 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 )
P R E S SP C A= ∑i = 1n∑j = 1d∣∣∣x( i )j- [ U( - i )[ U( - i )- j]+x( i )- j]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 )x( i )jx( i )- j∈ Rd- 1x^( i )jjx(i)−jU(−i)z^Rkx(i)−j dengan menghitung mana adalah dengan baris ke- ditendang keluar, dan singkatan dari pseudoinverse. Sekarang petakan kembali ke ruang aslinya: dan mengambil koordinat -nya . z^=[U(−i)−j]+x(i)−j∈RkU(−i)−jU(−i)j[⋅]+z^U(−i)[U(−i)−j]+x(i)−jj[⋅]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):x(i)−jz^approx=[U(−i)−j]⊤x(i)−j
PRESSPCA,approx=∑i=1n∑j=1d∣∣∣x(i)j−[U(−i)[U(−i)−j]⊤x(i)−j]j∣∣∣2=∑i=1n∥∥(I−UU⊤+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 U ⊤U(−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.
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')
tempRepmat(kk,kk) = -1
garis? Bukankah baris sebelumnya sudah memastikan bahwa itutempRepmat(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?