Những gì bạn đang làm là sai: không có nghĩa gì khi tính toán BÁO CHÍ cho PCA như thế! Cụ thể, vấn đề nằm ở bước 5 của bạn.
Cách tiếp cận ngây thơ để PRESS cho PCA
Hãy tập dữ liệu gồm điểm trong d không gian ba chiều: x ( i ) ∈ R d ,ndx(i)∈Rd,i=1…nx(i)X(−i)kU(−i)iPRESS ? = n ∑ i = 1 ‖ x ( i ) - U ( -∥∥x(i)−x^(i)∥∥2=∥∥x(i)−U(−i)[U(−i)]⊤x(i)∥∥2i
PRESS=?∑i=1n∥∥x(i)−U(−i)[U(−i)]⊤x(i)∥∥2.
Để đơn giản, tôi bỏ qua các vấn đề định tâm và nhân rộng ở đây.
Cách tiếp cận ngây thơ là sai
Vấn đề ở trên là chúng tôi sử dụng để tính toán dự đoán và đó là một điều rất tồi tệ.x(i)x^(i)
Lưu ý sự khác biệt quan trọng đối với trường hợp hồi quy, trong đó công thức cho lỗi tái cấu trúc về cơ bản là giống nhau , nhưng dự đoán được tính bằng các biến dự đoán và không sử dụng . Điều này là không thể trong PCA, bởi vì trong PCA không có biến phụ thuộc và độc lập: tất cả các biến được xử lý cùng nhau.∥∥y(i)−y^(i)∥∥2y^(i)y(i)
Trong thực tế, điều đó có nghĩa là PRESS như được tính toán ở trên có thể giảm khi số lượng thành phần tăng lên và không bao giờ đạt đến mức tối thiểu. Điều đó sẽ dẫn người ta nghĩ rằng tất cả các thành phần là đáng kể. Hoặc có thể trong một số trường hợp, nó đạt đến mức tối thiểu, nhưng vẫn có xu hướng quá phù hợp và đánh giá quá cao chiều tối ưu.kd
Một cách tiếp cận đúng
Có một số cách tiếp cận có thể, xem Bro et al. (2008) Xác thực chéo các mô hình thành phần: cái nhìn quan trọng về các phương pháp hiện tại để có cái nhìn tổng quan và so sánh. Một cách tiếp cận là loại bỏ một chiều của một điểm dữ liệu tại một thời điểm (ví dụ thay vì ), để dữ liệu đào tạo trở thành ma trận với một giá trị bị thiếu và sau đó để dự đoán ("tạp chất") giá trị còn thiếu này với PCA. (Tất nhiên người ta có thể giữ ngẫu nhiên một số phần tử ma trận lớn hơn, ví dụ 10%). Vấn đề là tính toán PCA với các giá trị bị thiếu có thể được tính toán khá chậm (nó dựa trên thuật toán EM), nhưng cần phải lặp đi lặp lại nhiều lần ở đây. Cập nhật: xem http://alexhwilliams.info/itsneuronalblog/2018/02/26/crossval/x(i)jx(i) để thảo luận tốt và triển khai Python (PCA với các giá trị bị thiếu được triển khai thông qua các bình phương tối thiểu xen kẽ).
Một cách tiếp cận mà tôi thấy thực tế hơn nhiều là bỏ qua một điểm dữ liệu tại một thời điểm, tính PCA trên dữ liệu đào tạo (chính xác như trên), nhưng sau đó lặp lại các kích thước của , bỏ chúng cùng một lúc và tính toán lỗi tái tạo bằng phần còn lại. Điều này có thể khá khó hiểu khi bắt đầu và các công thức có xu hướng trở nên khá lộn xộn, nhưng việc thực hiện khá đơn giản. Trước tiên tôi xin đưa ra công thức (hơi đáng sợ), và sau đó giải thích ngắn gọn về nó:x(i)x(i)
PRESSPCA=∑i=1n∑j=1d∣∣∣x(i)j−[U(−i)[U(−i)−j]+x(i)−j]j∣∣∣2.
Hãy xem xét các vòng lặp bên trong ở đây. Chúng tôi đã bỏ qua một điểm và tính thành phần chính trên dữ liệu đào tạo, . Bây giờ chúng tôi giữ từng giá trị làm thử nghiệm và sử dụng các kích thước còn lại để thực hiện dự đoán . Dự đoán là tọa độ thứ của "phép chiếu" (theo nghĩa bình phương nhỏ nhất) của trên không gian con được kéo dài bởi . Để tính toán, hãy tìm một điểm trong không gian PC gần nhất vớix(i)kU(−i)x(i)jx(i)−j∈Rd−1x^(i)jjx(i)−jU(−i)z^Rkx(i)−j bằng cách tính toán trong đó là với hàng thứ đá ra và là viết tắt của giả. Bây giờ ánh xạ trở lại không gian ban đầu: và lấy tọa độ thứ . z^=[U(−i)−j]+x(i)−j∈RkU(−i)−jU(−i)j[⋅]+z^U(−i)[U(−i)−j]+x(i)−jj[⋅]j
Một cách gần đúng với cách tiếp cận đúng
Tôi hoàn toàn không hiểu chuẩn hóa bổ sung được sử dụng trong PLS_Toolbox, nhưng đây là một cách tiếp cận theo cùng một hướng.
Có một cách khác để ánh xạ vào không gian của các thành phần chính: , tức là chỉ cần chuyển đổi thay vì giả nghịch đảo. Nói cách khác, kích thước còn lại để thử nghiệm hoàn toàn không được tính và các trọng số tương ứng cũng chỉ đơn giản là bị loại ra. Tôi nghĩ rằng điều này nên ít chính xác hơn, nhưng thường có thể được chấp nhận. Điều tốt là công thức kết quả bây giờ có thể được vector hóa như sau (Tôi bỏ qua tính toán):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,
trong đó tôi đã viết là cho sự gọn nhẹ và có nghĩa là đặt tất cả các phần tử không chéo thành 0. Lưu ý rằng công thức này trông giống hệt như công thức đầu tiên (PRESS ngây thơ) với một hiệu chỉnh nhỏ! Cũng lưu ý rằng việc hiệu chỉnh này chỉ phụ thuộc vào đường chéo của , giống như trong mã PLS_Toolbox. Tuy nhiên, công thức vẫn khác với những gì dường như được triển khai trong PLS_Toolbox và sự khác biệt này tôi không thể giải thích. U d i một g {⋅} U U ⊤U(−i)Udiag{⋅}UU⊤
Cập nhật (Tháng 2 năm 2018): Ở trên tôi đã gọi một thủ tục là "chính xác" và một "gần đúng" khác nhưng tôi không chắc chắn nữa rằng điều này có ý nghĩa. Cả hai thủ tục đều có ý nghĩa và tôi nghĩ không đúng hơn. Tôi thực sự thích rằng thủ tục "gần đúng" có một công thức đơn giản hơn. Ngoài ra, tôi nhớ rằng tôi đã có một số tập dữ liệu trong đó thủ tục "gần đúng" mang lại kết quả trông có ý nghĩa hơn. Thật không may, tôi không nhớ các chi tiết nữa.
Ví dụ
Dưới đây là cách các phương thức này so sánh cho hai bộ dữ liệu nổi tiếng: bộ dữ liệu Iris và bộ dữ liệu rượu vang. Lưu ý rằng phương pháp ngây thơ tạo ra một đường cong giảm đơn điệu, trong khi hai phương pháp khác mang lại một đường cong với mức tối thiểu. Lưu ý thêm rằng trong trường hợp Iris, phương pháp gần đúng gợi ý 1 PC là số tối ưu nhưng phương pháp giả cho thấy 2 PC. .
Mã Matlab để thực hiện xác nhận chéo và vẽ kết quả
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
dòng là gì? Không phải dòng trước đã đảm bảotempRepmat(kk,kk)
bằng -1? Ngoài ra, tại sao lại có lỗi? Dù sao thì lỗi cũng sẽ được bình phương, vì vậy tôi có hiểu chính xác rằng nếu các lỗi được loại bỏ, sẽ không có gì thay đổi?