Ana bileşenlerin sayısını belirlemek için PCA için çapraz doğrulama nasıl yapılır?


12

Temel bileşen analizi için kendi fonksiyonumu yazmaya çalışıyorum, PCA (tabii ki zaten yazılmış çok şey var ama sadece kendi başıma bir şeyler uygulamakla ilgileniyorum). Karşılaştığım temel sorun çapraz doğrulama adımı ve öngörülen karelerin toplamının (PRESS) hesaplanmasıdır. Hangi çapraz doğrulamayı kullandığım önemli değil, esasen arkasındaki teori ile ilgili bir soru, ancak bir kerelik izinsiz çapraz doğrulamayı (LOOCV) düşünün. Teoriden, LOOCV gerçekleştirmek için şunları yapmanız gerektiğini öğrendim:

  1. bir nesneyi sil
  2. gerisini ölçekle
  3. çok sayıda bileşenle PCA gerçekleştirin
  4. Silinen nesneyi (2) 'de elde edilen parametrelere göre ölçeklendirin
  5. PCA modeline göre nesneyi tahmin edebilir
  6. bu nesne için PRESS hesapla
  7. aynı algoritmayı diğer nesnelere yeniden uygulayın
  8. tüm PRESS değerlerini toplayın
  9. kâr

Alanda çok yeni olduğum için, doğru olduğumdan emin olmak için, sonuçları bazı yazılımların çıktılarıyla karşılaştırırım (ayrıca bir kod yazmak için yazılımdaki talimatları izlerim). Kareler ve kalan toplamını hesaplarken tamamen aynı sonuçları alıyorum , ancak PRESS'i hesaplamak bir problem.R2

Çapraz doğrulama adımında uyguladığım şeyin doğru olup olmadığını bana söyler misiniz?

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);

Yazılımda ( PLS_Toolbox ) şu şekilde çalışır:

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

Bu nedenle, bu tempRepmatdeğişkeni kullanarak bazı ek normalizasyonlar yapıyorlar : Bulduğum tek sebep, sağlam PCA için LOOCV uygulamasıydı. Maalesef destek ekibi, yazılımlarının yalnızca demo versiyonuna sahip olduğum için sorumu cevaplamak istemedi.


Ek normalleştirme snippet'ini anlayıp anlamadığımı kontrol edin: tempRepmat(kk,kk) = -1hattın rolü nedir? Önceki satır zaten tempRepmat(kk,kk)-1'e eşit değil mi? Ayrıca neden eksiler? Hata yine de kare olacak, bu yüzden eksileri kaldırılırsa hiçbir şeyin değişmeyeceğini doğru anladım mı?
amip

Geçmişte kontrol ediyordum ve hiçbir şey değişmeyecek. Bu doğru. Sadece sağlam PCA uygulamaları ile bazı paralellikler buldum çünkü böyle bir uygulamada hesaplanan her PRESS değerinin (her şeyi özetlemeden önce) kendi ağırlığı vardır.
Kirill

Ben cevap verilen MATLAB koduna eşdeğer R kodu arıyorum ve bir lütuf var.
AIM_BLB

3
@CSA, kod istemek burada konu dışı (muhtemelen, yorum ve ödüller yoluyla). Üzerinde sormak gerekir yığın taşması : Eğer kodu kopyalayıp w / Burada bir bağlantı kaynaktan alıntı, & bir çeviri için sorabilirsiniz. Bu konuda her şeyin olacağına inanıyorum.
gung - Monica'yı eski

Yanıtlar:


21

Yaptığınız şey yanlış: PCA için PRESS'i böyle hesaplamak mantıklı değil! Özellikle, sorun 5. adımınızda yatmaktadır.


PCA için PRESS'e naif yaklaşım

Veri kümesi oluşur olsun noktaları D : boyutlu uzayda x ( i )R, d ,ndx(i)Rd,i=1nx(i)X(i)kU(i)x(i)x^(i)2=x(i)U(i)[U(i)]x(i)2P R E S S ? = n i = 1x ( i ) - U ( - i ) [ U ( - i ) ] x ( i ) 2 .i

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

Kolaylık olması açısından, burada merkezleme ve ölçekleme konularını görmezden geliyorum.

Saf yaklaşım yanlış

Yukarıdaki sorun kullandığımız olmasıdır tahmin hesaplamak için , ve bu çok kötü bir şey olduğunu.x ( i )x(i)x^(i)

Yeniden oluşturma hatası formülünün temelde aynı olduğu bir regresyon senaryosundaki önemli farka dikkat edin , ancak tahmini , değil , tahmin değişkenleri kullanılarak hesaplanır . PCA'da bu mümkün değildir, çünkü PCA'da bağımlı ve bağımsız değişkenler yoktur: tüm değişkenler birlikte ele alınır.y(i)y^(i)2y^(i)y(i)

Pratikte bu, yukarıda hesaplandığı gibi PRESS'in artan sayıda bileşen ile azalabileceği ve asla minimum seviyeye ulaşamayacağı anlamına gelir . Bu da tüm bileşenlerinin önemli olduğunu düşünmesini sağlayacaktır . Ya da belki bazı durumlarda asgari seviyeye ulaşır, ancak yine de optimal boyutluluğa fazla uyma ve fazla tahmin etme eğilimi gösterir.kd

Doğru yaklaşım

Birkaç olası yaklaşım vardır, bakınız Bro ve ark. (2008) Bileşen modellerinin çapraz doğrulaması: genel bir bakış ve karşılaştırma için mevcut yöntemlere eleştirel bir bakış. Bir yaklaşım, bir kerede bir veri noktasının bir boyutunu dışarıda bırakmaktır (yani , yerine ), böylece eğitim verileri bir eksik değere sahip bir matris haline gelir ve sonra bu eksik değeri PCA ile tahmin etmek ("impute"). (Tabii ki, matris elemanlarının daha büyük bir kısmını, örneğin% 10'u rastgele tutabilir). Sorun, PCA'nın eksik değerlerle hesaplanmasının hesaplama olarak oldukça yavaş olabilmesidir (EM algoritmasına dayanır), ancak burada birçok kez tekrarlanması gerekir. Güncelleme: bkz. Http://alexhwilliams.info/itsneuronalblog/2018/02/26/crossval/xj(i)x(i) güzel bir tartışma ve Python uygulaması için (eksik değerlere sahip PCA, alternatif en küçük kareler aracılığıyla uygulanır).

Çok daha pratik bulduğum bir yaklaşım, bir seferde bir veri noktasını bırakmak , eğitim verilerinde PCA'yı (tam olarak yukarıdaki gibi) hesaplamak, ancak , bunları teker teker bırakın ve geri kalanını kullanarak bir yeniden oluşturma hatası hesaplayın. Bu başlangıçta oldukça kafa karıştırıcı olabilir ve formüller oldukça dağınık olma eğilimindedir, ancak uygulama oldukça basittir. Önce (biraz korkutucu) formülü vereyim ve sonra kısaca açıklayayım:x(i)x(i)

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

Buradaki iç döngüyü düşünün. Bir noktayı bıraktık ve eğitim verilerinde temel bileşenlerini hesapladık . Şimdi, her bir değer tutmak test olarak ve geri kalan boyutlarını kullanmak gerçekleştirmek için kestirim . Kestirim olan arasında (en küçük kareler), "çıkıntı" koordinatı inci matrisini yayılmış tarafından . Bunu hesaplamak için, bir nokta bulmak PC uzayda en yakın olanx(i)kU(i)xj(i)xj(i)Rd1x^j(i)jxj(i)U(i)z^Rkxj(i) hesaplanarak burada olduğunu ile -inci satır başladı ve yalancı ters anlamına gelir. Şimdi i orijinal boşluğa geri : ve koordinatını alın . z^=[Uj(i)]+xj(i)RkUj(i)U(i)j[]+z^U(i)[Uj(i)]+xj(i)j[]j

Doğru yaklaşıma yaklaşım

PLS_Toolbox'ta kullanılan ek normalleştirmeyi tam olarak anlamıyorum, ama burada aynı yöne giden bir yaklaşım var.

temel bileşenlerin alanı ile eşlemenin başka bir yolu daha vardır : , yani yalnızca sahte ters yerine devri al. Başka bir deyişle, test için dışarıda bırakılan boyut hiç sayılmaz ve karşılık gelen ağırlıklar da basitçe dışarı atılır. Bunun daha az doğru olması gerektiğini düşünüyorum, ancak çoğu zaman kabul edilebilir olabilir. İyi olan şey, ortaya çıkan formülün şimdi aşağıdaki gibi vektörleştirilebilmesidir (hesaplamayı atlarım):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,

burada kompaktlık için olarak yazdım ve tüm çapraz olmayan öğeleri sıfıra ayarlamak anlamına geliyor. Bu formülün, küçük bir düzeltmeyle tam olarak ilk formüle (saf PRESS) benzediğini unutmayın! Bu düzeltmenin PLS_Toolbox kodunda olduğu gibi yalnızca diyagonaline bağlı olduğunu da unutmayın . Bununla birlikte, formül hala PLS_Toolbox'ta uygulanmış gibi görünüyor ve bu farkı açıklayamıyorum. U d i a g {} U UU(i)Udiag{}UU

Güncelleme (Şubat 2018): Yukarıda bir prosedürü "doğru" ve başka bir "yaklaşık" olarak adlandırdım, ancak artık bunun anlamlı olduğundan emin değilim. Her iki prosedür de mantıklı ve bence ikisi de daha doğru değil. "Yaklaşık" prosedürünün daha basit bir formüle sahip olmasını gerçekten seviyorum. Ayrıca, "yaklaşık" prosedürünün daha anlamlı görünen sonuçlar verdiği bazı veri setim olduğunu hatırlıyorum. Ne yazık ki, artık ayrıntıları hatırlamıyorum.


Örnekler

Bu yöntemlerin iyi bilinen iki veri kümesi için karşılaştırması: Iris veri kümesi ve şarap veri kümesi. Naif yöntemin monoton olarak azalan bir eğri oluşturduğunu, diğer iki yöntemin ise minimum bir eğri verdiğini unutmayın. İris durumunda, yaklaşık yöntemin en uygun sayı olarak 1 PC önerdiğini, ancak sözde ters yöntemin 2 PC önerdiğini unutmayın. (Ve Iris veri kümesi için herhangi bir PCA dağılım grafiğine bakıldığında, her iki ilk PC'nin de bir miktar sinyal taşıdığı görülüyor.) Ve şarap durumunda, sahte ters yöntem açıkça 3 PC'yi gösteriyor, ancak yaklaşık yöntem 3 ile 5 arasında karar veremiyor.

resim açıklamasını buraya girin


Çapraz doğrulama yapmak ve sonuçları çizmek için Matlab kodu

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')

Cevabınız için teşekkür ederim! O kağıdı biliyorum. Ve orada açıklanan satır bazında çapraz doğrulama uyguladım (tam olarak verdiğim koda karşılık geliyor gibi görünüyor). PLS_Toolbox yazılımı ile karşılaştırın ama LOOCV içinde gerçekten anlamadığım bir kod satırı var (orijinal soruya yazdım).
Kirill

Evet, buna "satır bazında çapraz doğrulama" diyorlar ve uygulamanız iyi görünüyor, ancak bunun çapraz doğrulama yapmanın (Bro ve arkadaşlarında ampirik olarak belirtildiği ve aynı zamanda gösterildiği gibi) kötü bir yol olduğunu lütfen unutmayın. asla kullanmayın! Anlamadığınız kod satırıyla ilgili olarak - sorunuzu güncelleyecek misiniz? Ne kastettiğinizden emin değilim.
amip

Mesele şu ki, bu uygulama CV'de minimum seviyeye ulaşma yeteneğine sahip gibi görünüyor.
Kirill

BASIN çok yakın LOO% etmektir açıklanan varyans - Bu iyi ya da kötü olduğunu söyleyemem, ama bir ihtiyacı farkında olmak kesinlikle bir şeydir. Ve% açıklanan varyans PCA modeli veri kümesinin sıralamasına yaklaştıkça 1'e yaklaşacak gibi, bu X PRESS 0'a x^x
yaklaşacaktır.

@Kirill: Teşekkürler, kod snippet'i şimdi mantıklıdır (belki de artık eski olan yukarıdaki yorumları kaldırabilirsiniz). Ne yapması gerektiği hakkında hiçbir fikrim yok, ama hesaplanan tahmin hatası minimum ulaşmak yaparsa, o zaman muhtemelen daha büyük (bileşen sayısı; yani kodunuzda değişken ) için bazı ceza veriyor . Dürüst olmak gerekirse, özellikle benim cevabımda tarif ettiğim gibi daha iyi yaklaşımlar olduğu göz önüne alındığında, (herhangi bir teorik gerekçe olmadığı sürece) böyle bir yöntemden şüpheci olurum. ki
amip

1

@ Amoeba'nın güzel cevabına daha da genel bir nokta eklemek için:

Denetlenen ve denetlenmeyen modeller arasındaki pratik ve önemli bir fark, denetlenmeyen modeller için neyi eşdeğer olarak neyi dikkate alacağınızı daha fazla düşünmeniz gerektiğidir.

Denetimli modelleri her zaman onların son çıkış var Bu konuda umurumda gerekmez şekilde: tanım ve inşaat tarafından, ile aynı anlama sahip iddiaları , doğrudan karşılaştırabilirsiniz böylece. y yy^y^y

Anlamlı performans ölçümleri oluşturmak için, modelin ne tür özgürlüklerinin uygulamanız için anlamsız olduğunu ve hangilerinin olmadığını düşünmeniz gerekir. Bu, bir çeşit Procrustes benzeri rotasyon / saygısızlıktan sonra, muhtemelen (genellikle?) Puanlara bir BASINCI yol açacaktır.

X BASIN Benim tahminim (şimdi 2 kod satırları ne yapmak için zaman yok - ama belki satırları adım ve bir göz?):

Tam rütbe modeline ulaşılıncaya kadar tipik olarak artacak bir uyum iyiliği veren bir ölçüden iyi bir model karmaşıklığı belirlemek için yararlı bir önlem almak için çok karmaşık modeller için ceza vermeniz gerekir. Bu da bu cezalandırmanın a) çok önemli olduğu ve b) cezanın ayarlanması seçilen karmaşıklığı ayarlayacağı anlamına gelir.


Yan not: Bu tip otomatik model karmaşıklığı optimizasyonuna çok dikkat ettiğimi eklemek isterim. Deneyimlerime göre, bu algoritmaların birçoğu sadece sahte nesnellik sağlar ve genellikle sadece belirli veri türleri için iyi çalışma pahasına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.