PCAの交差検証を実行して主成分の数を決定する方法は?


12

主成分分析用の独自の関数であるPCAを記述しようとしています(もちろん、既に多くの記述がありますが、自分で実装することに興味があります)。私が遭遇した主な問題は、交差検証ステップと予測二乗和(PRESS)の計算です。どの交差検証を使用するかは関係ありません。これは主に背後にある理論についての質問ですが、Leave-one-out交差検証(LOOCV)を検討してください。理論から、LOOCVを実行するには次のことが必要であることがわかりました。

  1. オブジェクトを削除する
  2. 残りをスケール
  3. いくつかのコンポーネントでPCAを実行する
  4. (2)で取得したパラメーターに従って削除されたオブジェクトをスケーリングする
  5. PCAモデルに従ってオブジェクトを予測する
  6. このオブジェクトのPRESSを計算します
  7. 同じアルゴリズムを他のオブジェクトに再実行する
  8. すべてのPRESS値を合計します
  9. 利益

私はこの分野で非常に新しいので、私が正しいことを確認するために、結果を私が持っているいくつかのソフトウェアからの出力と比較します(また、いくつかのコードを書くために、ソフトウェアの指示に従います)。残差二乗和とを計算するとまったく同じ結果が得られますが、R2PRESSの計算は問題です。

相互検証ステップで実装することが正しいかどうか教えてください。

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

ソフトウェア(PLS_Toolbox)では、次のように機能します。

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

したがって、このtempRepmat変数を使用して追加の正規化を行います。私が見つけた唯一の理由は、堅牢なPCAにLOOCVを適用したことです。残念ながら、私はソフトウェアのデモ版しかないので、サポートチームは私の質問に答えたくありませんでした。


追加の正規化スニペットを理解しているかどうかをさらに確認しtempRepmat(kk,kk) = -1ます。ラインの役割は何ですか?前の行でtempRepmat(kk,kk)-1が保証されていませんか?また、なぜマイナス?とにかくエラーは二乗されるので、マイナスが削除されても何も変化しないことを正しく理解できますか?
アメーバはモニカを復活させます

私は過去にそれをチェックしていました、そして何も変わらないでしょう。そのとおりです。そのような実装で計算されたすべてのPRESS値(すべてを合計する前)には独自の重みがあるため、堅牢なPCA実装との類似点は一部だけでした。
Kirill

私は答えで提供されているMATLABコードと同等のRコードを探していて、賞金を上げました。
AIM_BLB 2018

3
@CSA、コードを要求することはここではトピック外です(おそらく、コメントと賞金を通じて)。あなたはStack Overflowでそれを尋ねることができるはずです:あなたはコードをコピーし、ここにリンク付きのソースを引用し、そして翻訳を求めることができます。私はそこにすべてのトピックがあると信じています。
ガン-モニカの

回答:


21

あなたがやっていることは間違っています:そのようなPCAのPRESSを計算するのは意味がありません!具体的には、問題はステップ5にあります。


PCA向けのPRESSに対するナイーブなアプローチ

ndx(i)Rd,i=1nx(i)X(i)kU(i)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.

簡単にするために、ここではセンタリングとスケーリングの問題を無視しています。

ナイーブなアプローチは間違っています

上記の問題は、を使用して予測を計算することです。これは非常に悪いことです。x(i)x^(i)

再構成エラーの式が基本的に同じ場合の重大な違いに注意してくださいが、予測 予測変数を使用して計算されていない使用して。PCAには依存変数と独立変数がないため、これはPCAでは不可能です。すべての変数は一緒に扱われます。y(i)y^(i)2y^(i)y(i)

実際には、上で計算されたPRESSは、コンポーネント数増加に伴って減少し、最小値に達することはありません。これにより、すべてのコンポーネントが重要であると考えるようになります。または、場合によっては最小値に達しますが、それでも最適な次元をオーバーフィットおよび過大評価する傾向があります。kd

正しいアプローチ

いくつかの可能なアプローチがあります、Bro et alを参照してください(2008)コンポーネントモデルの相互検証:概要と比較のための現在の方法の批評的考察。1つのアプローチは、一度に1つのデータポイントの1次元を除外することです(つまり、ではなく)。これにより、トレーニングデータは1つの欠損値を持つ行列になります。 、次にPCAでこの欠損値を予測(「計算」)します。(もちろん、ランダムにマトリックス要素の一部を大きくすることができます(例:10%))。問題は、欠損値を含むPCAの計算は非常に遅い(EMアルゴリズムに依存する)可能性があることですが、ここでは何度も繰り返す必要があります。更新:http : //alexhwilliams.info/itsneuronalblog/2018/02/26/crossval/を参照xj(i)x(i) 素敵な議論とPythonの実装(欠損値のあるPCAは最小二乗を交互に実行することで実装されます)。

私がはるかに実用的であることがわかったアプローチは、一度に1つのデータポイントを除外し、トレーニングデータでPCAを計算し(上記とまったく同じ)、次元をループすることです、一度に1つずつ省略し、残りを使用して再構成エラーを計算します。これは最初はかなり混乱する可能性があり、式はかなり乱雑になる傾向がありますが、実装はかなり簡単です。最初に(やや怖い)公式を示し、次に簡単に説明します。x(i)x(i)

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

ここで内側のループを考えます。1つの点を省略し、トレーニングデータの主成分、を計算しました。次に、各値をテストとして保持し、残りの次元を使用して予測を実行します。予測は、スパンされた部分空間への最小二乗の意味で)「射影」の番目の座標です。これを計算するには、PC空間、最も近い点を見つけますx(i)kU(i)xj(i)xj(i)Rd1x^j(i)jxj(i)U(i)z^Rkxj(i)計算してであると番目の行キックアウトされ、は疑似逆行列を表します。次に、を元の空間にマッピングします。とその番目の座標を取ります。 z^=[Uj(i)]+xj(i)RkUj(i)U(i)j[]+z^U(i)[Uj(i)]+xj(i)j[]j

正しいアプローチへの近似

PLS_Toolboxで使用されている追加の正規化についてはよくわかりませんが、同じ方向に進む1つの方法を次に示します。

を主成分の空間にマッピングする別の方法があります:、つまり疑似逆ではなく単に転置します。つまり、テストのために除外されたディメンションはまったくカウントされず、対応する重みも単純に除外されます。これは正確さは劣ると思いますが、多くの場合は許容できるかもしれません。良いことは、結果の数式が次のようにベクトル化できることです(計算は省略します)。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,

私が書いた場合として小型化のために、そしてゼロにすべての非対角要素を設定する手段。この式は、少し修正した最初の式(ナイーブプレス)のように見えることに注意してください。また、この修正は、PLS_Toolboxコードのように、の対角線にのみ依存することにも注意してください。ただし、式はPLS_Toolboxで実装されているように見えるものとはまだ異なり、この違いは説明できません。 U 、D 、I 、G {} U UU(i)Udiag{}UU

更新(2018年2月):上記の手順の1つを「正しい」と「おおよその」と呼びましたが、これが意味のあるものかどうか確信が持てなくなりました。どちらの手順にも意味があり、どちらも正しいとは思いません。「おおよそ」の手順の方が簡単な式になっているのがとても気に入っています。また、「近似」手順でより意味のある結果が得られるデータセットがあったことを覚えています。残念ながら、詳細はもう覚えていません。


これらのメソッドが2つの有名なデータセット、アイリスデータセットとワインデータセットを比較する方法を次に示します。ナイーブな方法は単調に減少する曲線を生成しますが、他の2つの方法は最小の曲線を生成することに注意してください。アイリスの場合、近似法は最適な数として1 PCを提案しますが、疑似逆法は2 PCを提案することに注意してください。(そして、IrisデータセットのPCA散布図を見ると、最初の両方のPCが何らかの信号を運んでいるように見えます。)そして、ワインの場合、疑似逆法は明らかに3つのPCを指していますが、近似法は3と5の間で決定できません。

ここに画像の説明を入力してください


交差検証を実行して結果をプロットするMatlabコード

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

回答ありがとうございます!私はその紙を知っています。そして、そこに記述されている行ごとの相互検証を適用しました(提供したコードに正確に対応しているようです)。私はPLS_Toolboxソフトウェアと比較しますが、LOOCVには1行のコードがあり、本当に理解できません(元の質問で書きました)。
Kirill

はい、彼らはそれを「行ごとの相互検証」と呼び、実装は問題ないように見えますが、これは相互検証を実行するための悪い方法であることに注意してください(Bro等で実証され、実証されています)。絶対に使用しないでください。わからないコード行について-質問を更新しますか?何を参照しているかわからない。
アメーバはモニカを復活させる

問題は、この実装にはCVで最小値に到達する機能があるようだということです。
Kirill

のPRESSはLOO%の説明された差異に非常に近いです-これが良いか悪いかはわかりませんが、それは明確に知っておく必要があるものです。PCAモデルがデータセットのランクに近づくと、%explained varianceが1に近づくように、このX PRESSは0に近づきますx^x
。– cbeleitesは、2014

@Kirill:おかげで、コードスニペットは今では意味をなしています(おそらく、廃止された上記のコメントを削除できます)。私はそれが何をすることになっているのか分かりませんが、それが計算された予測誤差を最小にすると言った場合、おそらくより大きな(コンポーネントの数、つまりコード内の変数)に対していくらかのペナルティをもたらします。正直なところ、私がそのような方法に懐疑的です(理論的に正当化されない限り)。特に、私の回答で説明した方法よりも良い方法があることを考えると。ki
アメーバはモニカを復活させます

1

@amoebaの良い答えにさらに一般的なポイントを追加するには:

監視ありモデルと監視なしモデルの実用的で重要な違いの1つは、監視なしモデルの場合、同等と見なすものとそうでないものをより深く考える必要があることです。

監視ありモデルは、常に彼らの最終的な出力持た定義や構造によって、:あなたはこのことについてあまり気にする必要はありません方法で、と同じ意味を持つように主張し、あなたがそれを直接比較することができますので、。 Y Yy^y^y

意味のあるパフォーマンス指標を構築するには、モデルのどのような種類の自由がアプリケーションにとって無意味であり、どれが無意味であるかを考える必要があります。それはおそらく、(通常は?)プロクラステスのような回転/反転の後に、スコアにPRESSを導きます。

xを押すと、私の推測は(2行のコードが何をしているのかを知る時間がないのですが、たぶん行を進めて見てみることができますか?):

通常、フルランクモデルに到達するまで増加する適合度を与えるメジャーから適切なモデルの複雑さを判断するのに役立つメジャーを取得するには、複雑すぎるモデルに対してペナルティを課す必要があります。つまり、このペナルティはa)重要であり、b)ペナルティを調整すると、選択した複雑さが調整されます。


補足:このタイプの自動化されたモデルの複雑さの最適化には非常に注意を払う必要があることを付け加えておきます。私の経験では、これらのアルゴリズムの多くは疑似客観性を生み出すだけであり、特定のタイプのデータに対してのみうまく機能するという犠牲を払うことがよくあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.