# I'm getting “jumpy” loadings in rollapply PCA in R. Can I fix it?

I have 10 years of daily returns data for 28 different currencies. I wish to extract the first principal component, but rather than operate PCA on the whole 10 years, I want to rollapply a 2 year window, because the currencies' behaviours evolve and so I wish to reflect this. However I have a major problem, that is that both the princomp() and prcomp() functions will often jump from positive to negative loadings in adjacent PCA analyses (ie 1 day apart). Have a look at the loading chart for the EUR currency:

Clearly I can't use this because adjacent loadings will jump from positive to negative, so my series which uses them will be erroneous. Now take a look at the absolute value of the EUR currency loading:

The problem is of course that I still cannot use this because you can see from the top chart that the loading does go from negative to positive and back at times, a characteristic which I need to preserve.

Is there any way I can get around this problem? Can I force the eigenvector orientation to always be the same in adjacent PCAs?

By the way this problem also occurs with the FactoMineR PCA() function. The code for the rollapply is here:

rollapply(retmat, windowl, function(x) summary(princomp(x))loadings[, 1], by.column = FALSE, align = "right") -> princomproll  - Could you explain what you mean by eigenvector "orientation"? As far as I know, there is no such thing that is intrinsic to the data. (That's one reason why different software will produce different normalized eigenvectors.) So it sounds like you're asking for something that does not exist and is meaningless. – whuber Aug 15 '12 at 20:20 Well on one day I'll get loadings like this: EUR -0.2 ZAR +0.8 USD +0.41 ..... 28 currencies. And the next day I'll get EUR +0.21 ZAR -0.79 USD -0.4 etc. So the axis that the PCA has chosen to rotate the data onto is oriented exactly the opposite way on day 2, compared with day 1. That is causing these loading jumps and I wish to avoid it, somehow......Apologies if my terminology is misleading. I understand that the PCA code doesn't really care about the axis orientation as long as it is consistent across loadings on one day, but I need it to be consistent across multiple days. – Thomas Browne Aug 15 '12 at 20:23 keeping in mind that from one day to the next, given a rolling 2 year window on daily data, we should have very, very similar PCA. – Thomas Browne Aug 15 '12 at 20:26 I think the reason that you have a problem is that this rollapply idea doesn't make sense. I have no solution other than to look for something different that may achieve your goals (not sure what they are) and is sensible. – Michael Chernick Aug 15 '12 at 20:38 EUR -0.2 ZAR +0.8 USD +0.41 and EUR +0.21 ZAR -0.79 USD -0.4 are very very similar. You simply invert sign in any of the two results. – ttnphns Aug 15 '12 at 20:46 show 3 more comments ## 2 Answers Whenever the plot jumps too much, reverse the orientation. One effective criterion is this: compute the total amount of jumps on all the components. Compute the total amount of jumps if the next eigenvector is negated. If the latter is less, negate the next eigenvector. Here's an implementation. (I am not familiar with zoo, which might allow a more elegant solution.) 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) }  As an example, let's run a random walk in an orthogonal group and jitter it a little for interest: 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,] }  Here's the rolling PCA: window <- 31 data <- zoo(x) result <- rollapply(data, window, function(x) summary(princomp(x))loadings[, 1], by.column = FALSE, align = "right")
plot(result)


Now the fixed version:

plot(amend(result))


-
Oh lovely. Thank you so much. –  Thomas Browne Aug 16 '12 at 9:01