Estoy recibiendo cargas "nerviosas" en rollapply PCA en R. ¿Puedo arreglarlo?

20

Tengo 10 años de datos de devoluciones diarias para 28 monedas diferentes. Deseo extraer el primer componente principal, pero en lugar de operar PCA en los 10 años completos, quiero implementar una ventana de 2 años, porque los comportamientos de las monedas evolucionan y, por lo tanto, deseo reflejar esto. Sin embargo, tengo un problema importante, que es que tanto las funciones princomp () como prcomp () a menudo saltan de cargas positivas a negativas en los análisis de PCA adyacentes (es decir, con 1 día de diferencia). Eche un vistazo a la tabla de carga para la moneda EUR:

ingrese la descripción de la imagen aquí

Claramente, no puedo usar esto porque las cargas adyacentes saltarán de positivo a negativo, por lo que mi serie que las usa será errónea. Ahora eche un vistazo al valor absoluto de la carga de divisas EUR:

ingrese la descripción de la imagen aquí

Por supuesto, el problema es que todavía no puedo usar esto porque puedes ver en la tabla superior que la carga va de negativa a positiva y viceversa, una característica que necesito preservar.

¿Hay alguna forma de evitar este problema? ¿Puedo forzar que la orientación del vector propio sea siempre la misma en PCA adyacentes?

Por cierto, este problema también ocurre con la función FactoMineR PCA (). El código para el rollapply está aquí:

rollapply(retmat, windowl, function(x) summary(princomp(x))$loadings[, 1], by.column = FALSE, align = "right") -> princomproll
Thomas Browne
fuente
3
¿Podría explicar qué quiere decir con "orientación" del vector propio? Hasta donde yo sé, no existe tal cosa que sea intrínseca a los datos. (Esa es una de las razones por las cuales diferentes programas producirán diferentes vectores propios normalizados). Entonces parece que está pidiendo algo que no existe y que no tiene sentido.
whuber
1
Bueno, un día obtendré cargas como esta: EUR -0.2 ZAR +0.8 USD +0.41 ..... 28 monedas. Y al día siguiente obtendré EUR +0.21 ZAR -0.79 USD -0.4 etc. Así que el eje en el que el PCA ha elegido rotar los datos está orientado exactamente en sentido opuesto el día 2, en comparación con el día 1. Eso está causando estos saltos de carga y deseo evitarlo, de alguna manera ... Disculpas si mi terminología es engañosa. Entiendo que el código PCA realmente no se preocupa por la orientación del eje, siempre y cuando sea consistente en las cargas en un día , pero necesito que sea consistente en varios días.
Thomas Browne
1
teniendo en cuenta que de un día para otro, dada una ventana de 2 años en datos diarios, deberíamos tener un PCA muy, muy similar.
Thomas Browne
Creo que la razón por la que tienes un problema es que esta idea de rollapply no tiene sentido. No tengo otra solución que buscar algo diferente que pueda lograr sus objetivos (no estoy seguro de cuáles son) y que sea sensato.
Michael R. Chernick
EUR -0.2 ZAR +0.8 USD +0.41y EUR +0.21 ZAR -0.79 USD -0.4 son muy muy parecidos. Simplemente invierte el signo en cualquiera de los dos resultados.
ttnphns

Respuestas:

22

Siempre que la trama salte demasiado, invierta la orientación. Un criterio efectivo es este: calcule la cantidad total de saltos en todos los componentes. Calcule la cantidad total de saltos si se niega el siguiente vector propio. Si este último es menor, niegue el siguiente vector propio.

Aquí hay una implementación. (No estoy familiarizado zoo, lo que podría permitir una solución más 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 ejemplo, corramos una caminata aleatoria en un grupo ortogonal y vibremos un poco por interés:

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,]
}

Aquí está el PCA rodante:

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

Original

Ahora la versión fija:

plot(amend(result))

Modificado

whuber
fuente
tyovyo+1yo+1vyoyo1-1vyo+1. Su algoritmo parece ser un poco diferente. ¿Funcionaría de la misma manera?
ameba dice Reinstate Monica
@amoeba Aunque no estoy muy seguro de lo que está haciendo exactamente, parece que algunas de las ideas discutidas en la respuesta de David J. Harris y los comentarios que siguen. Vea, en particular, mi comentario en stats.stackexchange.com/questions/34396/… .
whuber
2
@Art, por lo que entiendo, desea corregir el signo del componente en función de algunas preferencias externas (externas a PCA). Esto está bien, pero así es como debes abordarlo. Primero haga lo PCA deslizante, asegurándose de que los signos sean consistentes. Y luego decida, basándose en algunos criterios adicionales, si voltear el componente completo o no. Por ejemplo, puede correlacionarlo con la tendencia del euro y, si la correlación es negativa, voltee el componente. O algo así. Esto depende completamente de su aplicación específica y de su conocimiento de dominio.
ameba dice Reinstate Monica
1
Estoy de acuerdo con la interpretación y recomendación de @ ameeba.
whuber
1
@amoeba: sí, tienes razón en esto, aunque ingenuamente pensé que podría haber alguna solución genérica que no dependa de series de tiempo específicas, algo así como "orientación real del vector" :) de todos modos, gracias por tu ayuda y sugerencias
Anónimo
8

@whuber tiene razón en que no hay una orientación que sea intrínseca a los datos, pero aún podría asegurar que sus vectores propios tengan una correlación positiva con algún vector de referencia.

Por ejemplo, puede hacer que las cargas de USD sean positivas en todos sus vectores propios (es decir, si la carga de USD es negativa, cambie los signos de todo el vector). La dirección general de su vector sigue siendo arbitraria (ya que podría haber usado EUR o ZAR como referencia), pero los primeros ejes de su PCA probablemente no salten tanto, especialmente porque sus ventanas corredizas son tan largo.

David J. Harris
fuente
77
Buena idea. Intenté esto primero (probablemente mientras publicabas esta respuesta :-). El problema es que las otras cargas pueden saltar. Para solucionar esto, base la elección del signo en la carga más grande. Todavía no hay dados: las cargas aún pueden saltar. El truco consiste en elegir cada vez la orientación que crea la menor perturbación en el vector de cargas del tiempo anterior.
whuber
44
@whuber Buen trabajo.
David J. Harris
1
Correcto, el signo de las cargas no importa (orientación). Algo que no se abordó fue que si realiza esto en diferentes paquetes de software, las diferencias entre paquetes son que un programa puede generar signos negativos (positivos) en cargas particulares, mientras que otro resulta en signos positivos (negativos) para las mismas cargas. Por lo tanto, los signos de los resultados finales en el gráfico de la serie 3 anterior podrían invertirse al usar otro paquete. Las cargas de vectores de referencia también podrían tener un cambio de signo, y esta solución no sería incorrecta.
JoleT
@LEP: Me enfrenté al mismo problema con la inversión, tal vez ya haya encontrado una solución para este problema: cómo descubrir que el primer vector es correcto y asegurarse de que el resto se alineará correctamente con él - quant.stackexchange.com/questions / 3094 / ... ?
Anónimo
Mientras la matriz no sea singular y ninguno de los valores propios sea cero, la mayoría de los resultados del algoritmo deberían ser los mismos, excepto por un cambio de 180 grados en los signos, lo que no está garantizado.
JoleT
1

Lo que hice fue calcular la distancia L1 entre sucesivos vectores propios. Después de normalizar esta matriz, elijo un umbral de puntaje az, por ejemplo, 1, de modo que si en cualquier nueva rotación el cambio está por encima de este umbral, volteo el vector propio, los factores y las cargas para tener consistencia en la ventana móvil. Personalmente, no me gusta forzar los signos dados en algunas correlaciones, ya que pueden ser muy volátiles dependiendo de los controladores de macro.

Raul Muñoz
fuente