Estou recebendo carregamentos "agitados" no rollAplicar PCA em R. Posso corrigi-lo?

20

Eu tenho 10 anos de dados de retornos diários para 28 moedas diferentes. Desejo extrair o primeiro componente principal, mas, em vez de operar o PCA nos 10 anos completos, quero aplicar uma janela de 2 anos, porque os comportamentos das moedas evoluem e, portanto, desejo refletir isso. No entanto, tenho um grande problema: as funções princomp () e prcomp () geralmente saltam de cargas positivas para negativas nas análises PCA adjacentes (ou seja, com um dia de intervalo). Veja a tabela de carregamento da moeda EUR:

insira a descrição da imagem aqui

Claramente, não posso usar isso porque os carregamentos adjacentes saltam de positivo para negativo; portanto, minha série que os utiliza será errônea. Agora, veja o valor absoluto do carregamento da moeda em euros:

insira a descrição da imagem aqui

Obviamente, o problema é que ainda não posso usar isso, porque você pode ver no gráfico superior que o carregamento passa de negativo para positivo e, às vezes, volta, uma característica que preciso preservar.

Existe alguma maneira de resolver esse problema? Posso forçar a orientação do vetor próprio para ser sempre a mesma em PCAs adjacentes?

A propósito, esse problema também ocorre com a função FactoMineR PCA (). O código para a aplicação cumulativa está aqui:

rollapply(retmat, windowl, function(x) summary(princomp(x))$loadings[, 1], by.column = FALSE, align = "right") -> princomproll
Thomas Browne
fonte
3
Você poderia explicar o que você quer dizer com "orientação" do vetor próprio? Até onde eu sei, não existe algo intrínseco aos dados. (Essa é uma das razões pelas quais softwares diferentes produzirão autovetores normalizados diferentes.) Parece que você está pedindo algo que não existe e que não tem sentido.
whuber
1
Bem, em um dia receberei carregamentos como este: EUR -0,2 ZAR +0,8 USD +0,41 ..... 28 moedas. E no dia seguinte receberei EUR +0,21 ZAR -0,79 USD -0,4 etc. Portanto, o eixo no qual o PCA optou por rotacionar os dados é orientado exatamente da maneira oposta no dia 2, comparado ao dia 1. Isso está causando estes saltos de carregamento e desejo evitá-lo, de alguma forma ...... Desculpas se minha terminologia é enganosa. Entendo que o código PCA realmente não se importa com a orientação do eixo, desde que seja consistente em todas as cargas em um dia , mas preciso que seja consistente em vários dias.
22612 Thomas
1
tendo em mente que, de um dia para o outro, com uma janela rolante de 2 anos nos dados diários, deveríamos ter um PCA muito, muito semelhante.
22612 Thomas
Acho que o motivo de você ter um problema é que essa ideia de aplicação não faz sentido. Não tenho outra solução senão procurar algo diferente que possa alcançar seus objetivos (não sei ao certo quais são) e que seja sensato.
Michael R. Chernick
EUR -0.2 ZAR +0.8 USD +0.41e EUR +0.21 ZAR -0.79 USD -0.4 são muito, muito parecidos. Você simplesmente inverte o sinal em qualquer um dos dois resultados.
ttnphns

Respostas:

22

Sempre que o gráfico saltar demais, inverta a orientação. Um critério eficaz é este: calcule a quantidade total de saltos em todos os componentes. Calcule a quantidade total de saltos se o próximo vetor próprio for negado. Se o último for menor, negue o próximo vetor próprio.

Aqui está uma implementação. (Não estou familiarizado zoo, o que pode permitir uma solução mais elegante.)

require(zoo)
amend <- function(result) {
  result.m <- as.matrix(result)
  n <- dim(result.m)[1]
  delta <- apply(abs(result.m[-1,] - result.m[-n,]), 1, sum)
  delta.1 <- apply(abs(result.m[-1,] + result.m[-n,]), 1, sum)
  signs <- c(1, cumprod(rep(-1, n-1) ^ (delta.1 <= delta)))
  zoo(result * signs)
}

Como exemplo, vamos fazer um passeio aleatório em um grupo ortogonal e instale-o um pouco por interesse:

random.rotation <- function(eps) {
  theta <- rnorm(3, sd=eps)
  matrix(c(1, theta[1:2], -theta[1], 1, theta[3], -theta[2:3], 1), 3)
}
set.seed(17)
n.times <- 1000
x <- matrix(1., nrow=n.times, ncol=3)
for (i in 2:n.times) {
  x[i,] <- random.rotation(.05) %*% x[i-1,]
}

Aqui está o PCA rotativo:

window <- 31
data <- zoo(x)
result <- rollapply(data, window, 
  function(x) summary(princomp(x))$loadings[, 1], by.column = FALSE, align = "right")
plot(result)

Original

Agora a versão fixa:

plot(amend(result))

Alterados

whuber
fonte
tEuvEu+1Eu+1vEuEu1-1vEu+1. Seu algoritmo parece ser um pouco diferente. Funcionaria da mesma maneira?
Ameba diz Reinstate Monica
@amoeba Embora eu não tenha muita certeza do que você está fazendo, parece que algumas das idéias discutidas na resposta de David J. Harris e nos comentários a seguir. Veja, em particular, meu comentário em stats.stackexchange.com/questions/34396/… .
whuber
2
@Art, pelo que entendi, você deseja corrigir o sinal do componente com base em algumas preferências externas (externas ao PCA). Isso é bom, mas é assim que você deve abordá-lo. Primeiro, faça a coisa deslizante do PCA, certificando-se de que os sinais sejam consistentes. E então decida, com base em alguns critérios adicionais, se é necessário inverter o componente inteiro ou não. Por exemplo, você pode correlacioná-lo com a tendência do euro e, se a correlação for negativa, inverta o componente. Ou algo assim. Isso depende inteiramente do seu aplicativo específico e do conhecimento do seu domínio.
Ameba diz Reinstate Monica
1
Concordo com a interpretação e recomendação de @ amoeba.
whuber
1
@amoeba: sim, você está certo sobre isso, embora eu tenha pensado ingenuamente que possa haver alguma solução genérica que não dependa de séries temporais específicas, algo como "orientação real do vetor" :) de qualquer maneira, obrigado pela ajuda e sugestões
Anônimo
8

A @whuber tem razão em não haver uma orientação intrínseca aos dados, mas você ainda pode garantir que seus autovetores tenham correlação positiva com algum vetor de referência.

Por exemplo, você pode tornar as cargas para USD positivas em todos os seus vetores próprios (ou seja, se a carga de USD for negativa, inverta os sinais do vetor inteiro). A direção geral do seu vetor ainda é arbitrária (já que você poderia ter usado EUR ou ZAR como referência), mas os primeiros eixos do seu PCA provavelmente não vão pular tanto - especialmente porque suas janelas são tão grandes.

David J. Harris
fonte
7
Boa ideia. Eu tentei isso primeiro (provavelmente enquanto você estava postando esta resposta :-). O problema é que os outros carregamentos podem pular. Para corrigir isso, baseie a opção de sinal no maior carregamento. Ainda não há dados: as cargas ainda podem pular. O truque é sempre escolher a orientação que cria o menor distúrbio no vetor de cargas do tempo anterior.
whuber
4
@whuber Bom trabalho.
18743 David J. Harris
1
Correto, o sinal de carregamento não importa (orientação). Algo que não foi abordado foi que, se você fizer isso em diferentes pacotes de software, as diferenças entre pacotes são que um programa pode resultar em sinais negativos (positivos) em determinados carregamentos, enquanto outro resulta em sinais positivos (negativos) para os mesmos carregamentos. Portanto, os sinais dos resultados finais no gráfico de 3 séries acima podem ser invertidos ao usar outro pacote. As cargas do vetor de referência também podem ter uma alteração de sinal - e essa solução não estaria incorreta.
Jolet
@LEP: Eu enfrentei o mesmo problema com a inversão, talvez você já tenha encontrado a solução para esse problema - como descobrir que o primeiro vetor está correto e garantir que o restante esteja alinhado a ele corretamente - quant.stackexchange.com/questions / 3094 / ... ?
Anônimo
Desde que a matriz não seja singular e nenhum dos autovalores seja zero, a maioria dos resultados do algoritmo deve ser a mesma, exceto por uma alteração de 180 graus nos sinais - o que não é garantido.
Jolet
1

O que fiz foi calcular a distância L1 entre os autovetores sucessivos. Depois de normalizar essa matriz, escolho o limiar de pontuação az, por exemplo, 1, para que, em qualquer rolagem nova, a mudança esteja acima desse limiar, inverta o vetor próprio, os fatores e as cargas para ter consistência na janela de rolagem. Pessoalmente, eu não gosto de forçar sinais dados em algumas correlações, pois elas podem ser muito voláteis, dependendo dos drivers de macro.

Raul Muñoz
fonte