Take the 2-minute tour ×
Cross Validated is a question and answer site for people interested in statistics, machine learning, data analysis, data mining, and data visualization. It's 100% free, no registration required.

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:

enter image description here

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:

enter image description here

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
share|improve this question
2  
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

2 Answers 2

up vote 16 down vote accepted

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)

Original

Now the fixed version:

plot(amend(result))

Amended

share|improve this answer
    
Oh lovely. Thank you so much. –  Thomas Browne Aug 16 '12 at 9:01

@whuber is right that there isn't an orientation that's intrinsic to the data, but you could still enforce that your eigenvectors have positive correlation with some reference vector.

For instance, you could make the loadings for USD positive on all your eigenvectors (i.e., if USD's loading is negative, flip the signs of the entire vector). The overall direction of your vector is still arbitrary (since you could have used EUR or ZAR as your reference instead), but the first few axes of your PCA probably won't jump around nearly as much--especially because your rolling windows are so long.

share|improve this answer
5  
Good idea. I tried this first (probably while you were posting this answer :-). The problem is that the other loadings can jump around. To fix this, base the sign choice on the largest loading. Still no dice: the loadings can still jump. The trick is at each time to choose the orientation that creates the least disturbance in the vector of loadings from the previous time. –  whuber Aug 15 '12 at 21:57
4  
@whuber Nice work. –  David J. Harris Aug 16 '12 at 0:17
    
Correct, the sign of loadings doesn't matter (orientation). Something that was not addressed was that if you perform this across different software packages, the between-package differences is that one program may result in negative(positive) signs on particular loadings while another results in positive(negative) signs for the same loadings. Therefore, the signs of the final results in the 3-series plot above could be inverted when using another package. The reference vector loadings could also have a sign change - and this solution would not be incorrect. –  LEP Jan 29 at 12:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.