O que você está fazendo está errado: não faz sentido calcular o PRESS para PCA dessa maneira! Especificamente, o problema está na etapa 5.
Abordagem ingênua do PRESS for PCA
Deixe o conjunto de dados constituído por pontos em espaço -dimensional: . Para calcular o erro de reconstrução para um único ponto de dados de teste , você executa o PCA no conjunto de treinamento com este ponto excluído, faça um determinado número de eixos principais como colunas de e localize o erro de reconstrução como . PRESS é então igual à soma de todas as amostras de tested x ( i ) ∈ R d ,ndx(i)∈Rd,i=1…nx(i)X(−i)kU(−i) i P∥∥x(i)−x^(i)∥∥2=∥∥x(i)−U(−i)[U(−i)]⊤x(i)∥∥2i, portanto, a equação razoável parece ser:
PRESS=?∑i=1n∥∥x(i)−U(−i)[U(−i)]⊤x(i)∥∥2.
Por simplicidade, estou ignorando os problemas de centralização e dimensionamento aqui.
A abordagem ingênua está errada
O problema acima é que usamos para calcular a previsão , e isso é uma coisa muito ruim.x(i)x^(i)
Observe a diferença crucial em um caso de regressão, onde a fórmula do erro de reconstrução é basicamente a mesma , mas a previsão é calculada usando as variáveis preditoras e não usando . Isso não é possível no PCA, porque no PCA não há variáveis dependentes e independentes: todas as variáveis são tratadas juntas.∥∥y(i)−y^(i)∥∥2y^(i)y(i)
Na prática, isso significa que o PRESS, conforme calculado acima, pode diminuir com o aumento do número de componentes e nunca atingir um mínimo. O que levaria a pensar que todos os componentes são significativos. Ou talvez, em alguns casos, atinja um mínimo, mas ainda tende a superestimar e superestimar a dimensionalidade ideal.kd
Uma abordagem correta
Existem várias abordagens possíveis, veja Bro et al. (2008) Validação cruzada de modelos de componentes: uma visão crítica dos métodos atuais para uma visão geral e comparação. Uma abordagem é deixar de fora uma dimensão de um ponto de dados por vez (ou seja, vez de ), para que os dados de treinamento se tornem uma matriz com um valor ausente e, em seguida, prever ("imputar") esse valor ausente no PCA. (É claro que é possível armazenar aleatoriamente uma fração maior de elementos da matriz, por exemplo, 10%). O problema é que a computação do PCA com valores ausentes pode ser computacionalmente bastante lenta (depende do algoritmo EM), mas precisa ser iterada várias vezes aqui. Atualização: consulte http://alexhwilliams.info/itsneuronalblog/2018/02/26/crossval/x(i)jx(i) para uma boa discussão e implementação do Python (o PCA com valores ausentes é implementado por meio de mínimos quadrados alternados).
Uma abordagem que achei muito mais prática é deixar de fora um ponto de dados cada vez, computar o PCA nos dados de treinamento (exatamente como acima), mas depois percorrer as dimensões de , deixe-os de fora um de cada vez e calcule um erro de reconstrução usando o resto. Isso pode ser bastante confuso no começo e as fórmulas tendem a se tornar bastante confusas, mas a implementação é bastante direta. Deixe-me primeiro dar a fórmula (um pouco assustadora) e depois explicá-la brevemente:x(i)x(i)
PRESSPCA=∑i=1n∑j=1d∣∣∣x(i)j−[U(−i)[U(−i)−j]+x(i)−j]j∣∣∣2.
Considere o loop interno aqui. Deixamos de lado um ponto e computamos componentes principais nos dados de treinamento, . Agora mantemos cada valor como teste e usamos as dimensões restantes para realizar a previsão . A previsão é a ésima coordenada da "projeção" (no sentido dos mínimos quadrados) de no subespaço estendido por . Para calcular, encontre um ponto no espaço do PC mais próximo de k U ( - i )x(i)kU(−i)x(i)jx(i)−j∈Rd−1x^(i)jjx(i)−jU(−i)z^Rkx(i)−j calculando onde é com -ésima linha expulso e significa pseudoinverso. Agora, mapeie volta ao espaço original: e assume a ésima coordenada . z^=[U(−i)−j]+x(i)−j∈RkU(−i)−jU(−i)j[⋅]+z^U(−i)[U(−i)−j]+x(i)−jj[⋅]j
Uma aproximação à abordagem correta
Não entendo bem a normalização adicional usada no PLS_Toolbox, mas aqui está uma abordagem que segue na mesma direção.
Existe outra maneira de mapear no espaço dos componentes principais: , ou seja, simplesmente faça a transposição em vez de pseudo-inversa. Em outras palavras, a dimensão que é deixada de fora para o teste não é contada, e os pesos correspondentes também são simplesmente expulsos. Eu acho que isso deve ser menos preciso, mas muitas vezes pode ser aceitável. O bom é que a fórmula resultante agora pode ser vetorizada da seguinte forma (eu omito o cálculo):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,
onde eu escrevi como para compacidade e significa definir todos os elementos não diagonais como zero. Observe que esta fórmula se parece exatamente com a primeira (IMPRENSA ingênua) com uma pequena correção! Observe também que essa correção depende apenas da diagonal de , como no código PLS_Toolbox. No entanto, a fórmula ainda é diferente do que parece ser implementado no PLS_Toolbox, e essa diferença não posso explicar. U d i a g {⋅} U U ⊤U(−i)Udiag{⋅}UU⊤
Atualização (fev 2018): Acima, chamei um procedimento de "correto" e outro de "aproximado", mas não tenho mais tanta certeza de que isso seja significativo. Ambos os procedimentos fazem sentido e acho que nenhum dos dois é mais correto. Eu realmente gosto que o procedimento "aproximado" tenha uma fórmula mais simples. Além disso, lembro que tinha um conjunto de dados em que o procedimento "aproximado" produzia resultados que pareciam mais significativos. Infelizmente, não me lembro mais dos detalhes.
Exemplos
Aqui está como esses métodos se comparam para dois conjuntos de dados conhecidos: conjunto de dados Iris e conjunto de dados wine. Observe que o método ingênuo produz uma curva monotonicamente decrescente, enquanto outros dois métodos produzem uma curva com um mínimo. Observe ainda que, no caso Iris, o método aproximado sugere 1 PC como o número ideal, mas o método pseudo-inverso sugere 2 PCs. (E olhando para qualquer gráfico de dispersão de PCA para o conjunto de dados Iris, parece que os dois primeiros PCs transmitem algum sinal.) E no caso do wine, o método pseudoinverso aponta claramente para 3 PCs, enquanto o método aproximado não pode decidir entre 3 e 5.
Código Matlab para executar validação cruzada e plotar os resultados
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
linha? A linha anterior já não está garantindo quetempRepmat(kk,kk)
seja igual a -1? Além disso, por que menos? O erro será quadrado de qualquer maneira, então eu entendi corretamente que se os menos foram removidos, nada mudará?