我在 R 中的 rollapply PCA 中得到“跳跃”负载。我可以修复它吗?

机器算法验证 r 主成分分析 移动窗口
2022-01-22 02:20:27

我有 28 种不同货币的 10 年每日回报数据。我希望提取第一个主成分,而不是在整个 10 年内运行 PCA,我想滚动应用 2 年窗口,因为货币的行为会演变,所以我希望反映这一点。但是我有一个主要问题,即在相邻的 PCA 分析(即相隔 1 天)中,princomp()prcomp()函数通常会从正负载跳到负负载。查看欧元货币的加载图表:

在此处输入图像描述

显然我不能使用它,因为相邻的载荷会从正值跳到负值,所以我使用它们的系列将是错误的。现在看一下欧元货币加载的绝对值:

在此处输入图像描述

问题当然是我仍然无法使用它,因为您可以从顶部图表中看到负载确实会从负变为正并有时会返回,这是我需要保留的特征。

有什么办法可以解决这个问题吗?我可以强制特征向量方向在相邻 PCA 中始终相同吗?

顺便说一句,FactoMineR PCA() 函数也会出现此问题。rollapply 的代码在这里:

rollapply(retmat, windowl, function(x) 
  summary(princomp(x))$loadings[, 1], by.column = FALSE, 
  align = "right") -> princomproll
3个回答

每当情节跳跃太多时,反转方向。 一个有效的标准是:计算所有组件的总跳跃量。如果下一个特征向量被否定,则计算跳跃的总量。如果后者小于,则否定下一个特征向量。

这是一个实现。(我不熟悉zoo,这可能允许更优雅的解决方案。)

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)
}

举个例子,让我们在一个正交组中随机游走,并稍微抖动一下以引起兴趣:

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

这是滚动 PCA:

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

原来的

现在是固定版本:

plot(amend(result))

修正

@whuber 是正确的,没有数据固有的方向,但是您仍然可以强制您的特征向量与某些参考向量具有正相关。

例如,您可以在所有特征向量上使 USD 的负载为正(即,如果 USD 的负载为负,则翻转整个向量的符号)。矢量的整体方向仍然是任意的(因为您可以使用 EUR 或 ZAR 作为参考),但是您的 PCA 的前几个轴可能不会跳动几乎一样多 - 特别是因为您的滚动窗口是如此长。

我所做的是计算连续特征向量之间的 L1 距离。在对这个矩阵进行归一化之后,我选择 az score 阈值,例如 1,这样如果在任何新的滚动中变化高于这个阈值,我就会翻转特征向量、因子和载荷,以便在滚动窗口中保持一致性。就我个人而言,我不喜欢在某些相关性中强加给定符号,因为它们可能非常不稳定,具体取决于宏观驱动因素。