测试矩阵列之间的线性相关性

机器算法验证 r 相关性 主成分分析 线性模型 svd
2022-01-18 03:00:45

我有一个行列式为零的证券收益相关矩阵。(这有点令人惊讶,因为样本相关矩阵和相应的协方差矩阵理论上应该是正定的。)

我的假设是,至少一种证券线性依赖于其他证券。R中是否有一个函数可以顺序测试每一列的线性相关性矩阵?

例如,一种方法是一次建立一个证券的相关矩阵,并在每一步计算行列式。当行列式 = 0 时停止,因为您已确定证券是其他证券的线性组合。

识别这种矩阵中的线性相关性的任何其他技术都是值得赞赏的。

4个回答

这是一个简单的方法:计算删除每一列所产生的矩阵的秩。移除后导致最高排名的列是线性相关的列(因为移除这些列不会降低排名,而移除线性独立的列会降低排名)。

在 R 中:

rankifremoved <- sapply(1:ncol(your.matrix), function (x) qr(your.matrix[,-x])$rank)
which(rankifremoved == max(rankifremoved))

该问题询问有关变量之间“识别潜在[线性]关系”的问题。

检测关系的快速简便的方法是使用您最喜欢的软件针对这些变量回归任何其他变量(使用常数,甚至):任何好的回归程序都可以检测和诊断共线性。(您甚至不必费心查看回归结果:我们只是依赖于设置和分析回归矩阵的有用副作用。)

但是,假设检测到共线性,接下来呢? 主成分分析(PCA) 正是我们所需要的:它的最小成分对应于近线性关系。这些关系可以直接从“载荷”中读取,它们是原始变量的线性组合。小载荷(即与小特征值相关的载荷)对应于近似共线性。特征值对应于完美的线性关系。仍然比最大值小得多的稍大的特征值将对应于近似线性关系。0

(有一种艺术和大量文献与识别什么是“小”负载有关。为了对因变量建模,我建议将其包含在 PCA 中的自变量中,以识别组件——无论它们的大小——其中因变量起着重要作用。从这个角度来看,“小”意味着比任何此类组件小得多。)


让我们看一些例子。 (这些R用于计算和绘图。)从执行 PCA 的函数开始,寻找小组件,绘制它们,并返回它们之间的线性关系。

pca <- function(x, threshold, ...) {
  fit <- princomp(x)
  #
  # Compute the relations among "small" components.
  #
  if(missing(threshold)) threshold <- max(fit$sdev) / ncol(x)
  i <- which(fit$sdev < threshold)
  relations <- fit$loadings[, i, drop=FALSE]
  relations <- round(t(t(relations) / apply(relations, 2, max)), digits=2)
  #
  # Plot the loadings, highlighting those for the small components.
  #
  matplot(x, pch=1, cex=.8, col="Gray", xlab="Observation", ylab="Value", ...)
  suppressWarnings(matplot(x %*% relations, pch=19, col="#e0404080", add=TRUE))

  return(t(relations))
}

让我们将其应用于一些随机数据。这些建立在四个变量(问题的)之上。这是一个将计算为其他给定线性组合的小函数。然后,它将 iid 正态分布值添加到所有五个变量(以查看当多重共线性只是近似而非精确时程序的执行情况)。B,C,D,EA

process <- function(z, beta, sd, ...) {
  x <- z %*% beta; colnames(x) <- "A"
  pca(cbind(x, z + rnorm(length(x), sd=sd)), ...)
}

我们都准备好了:剩下的只是生成并应用这些过程。我使用问题中描述的两种情况:(每个都有一些错误)和(每个都有一些错误)。然而,首先请注意,PCA 几乎总是应用于居中数据,因此这些模拟数据使用.B,,EA=B+C+D+EA=B+(C+D)/2+Esweep

n.obs <- 80 # Number of cases
n.vars <- 4 # Number of independent variables
set.seed(17)
z <- matrix(rnorm(n.obs*(n.vars)), ncol=n.vars)
z.mean <- apply(z, 2, mean)
z <- sweep(z, 2, z.mean)
colnames(z) <- c("B","C","D","E") # Optional; modify to match `n.vars` in length

在这里,我们采用了两种情况,每种情况都应用了三个级别的错误。原始变量始终保持不变:只有和误差项有所不同。B,,EA

结果

与左上面板相关的输出是

       A  B  C  D  E
Comp.5 1 -1 -1 -1 -1

这表示红点行 - 始终为,表明完美的多重共线性 - 由组合:正是指定的内容。00ABCDE

上中间面板的输出是

       A     B     C     D     E
Comp.5 1 -0.95 -1.03 -0.98 -1.02

系数仍然接近我们的预期,但由于引入的误差,它们并不完全相同。所暗示的五维空间内加厚了四维超平面,并且使估计的方向稍微倾斜。随着误差的增加,加厚变得与点的原始分布相当,使得超平面几乎无法估计。现在(在右上角的面板中)系数是(A,B,C,D,E)

       A     B     C     D     E
Comp.5 1 -1.33 -0.77 -0.74 -1.07

它们已经发生了很大变化,但仍然反映了基本的潜在关系其中素数表示删除了(未知)错误的值。A=B+C+D+E

底行的解释方式相同,其输出同样反映了系数1,1/2,1/2,1

在实践中,通常不会将一个变量单独挑出来作为其他变量的明显组合:所有系数可能具有可比的大小和不同的符号。此外,当关系有多个维度时,没有唯一的方法来指定它们:需要进一步分析(例如行缩减)来确定这些关系的有用基础。这就是世界的运作方式:您只能说,PCA 输出的这些特定组合几乎不对应于数据的任何变化。 为了解决这个问题,有些人在回归或后续分析中直接使用最大(“主”)分量作为自变量,无论采用何种形式。如果这样做,请不要忘记首先从变量集中删除因变量并重做 PCA!


这是重现此图的代码:

par(mfrow=c(2,3))
beta <- c(1,1,1,1) # Also can be a matrix with `n.obs` rows: try it!
process(z, beta, sd=0, main="A=B+C+D+E; No error")
process(z, beta, sd=1/10, main="A=B+C+D+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+C+D+E; Large error")

beta <- c(1,1/2,1/2,1)
process(z, beta, sd=0, main="A=B+(C+D)/2+E; No error")
process(z, beta, sd=1/10, main="A=B+(C+D)/2+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+(C+D)/2+E; Large error")

(我不得不在大错误情况下调整阈值,以便只显示一个组件:这就是将此值作为参数提供给的原因process。)


用户 ttnphns 将我们的注意力引向了一个密切相关的线程。 它的一个答案(由 JM 提供)建议使用此处描述的方法。

您似乎问了一个非常发人深省的问题:在给定奇异相关(或协方差,或平方和叉积)矩阵的情况下,如何检测哪一列线性依赖于哪一列。我暂时认为扫描操作会有所帮助。这是我在 SPSS(不是 R)中的探测来说明。

让我们生成一些数据:

        v1        v2        v3         v4          v5
    -1.64454    .35119   -.06384    -1.05188     .25192
    -1.78520   -.21598   1.20315      .40267    1.14790
     1.36357   -.96107   -.46651      .92889   -1.38072
     -.31455   -.74937   1.17505     1.27623   -1.04640
     -.31795    .85860    .10061      .00145     .39644
     -.97010    .19129   2.43890     -.83642    -.13250
     -.66439    .29267   1.20405      .90068   -1.78066
      .87025   -.89018   -.99386    -1.80001     .42768
    -1.96219   -.27535    .58754      .34556     .12587
    -1.03638   -.24645   -.11083      .07013    -.84446

让我们在 V2、V4 和 V5 之间创建一些线性依赖关系:

compute V4 = .4*V2+1.2*V5.
execute.

因此,我们修改了我们的列 V4。

matrix.
get X. /*take the data*/
compute M = sscp(X). /*SSCP matrix, X'X; it is singular*/
print rank(M). /*with rank 5-1=4, because there's 1 group of interdependent columns*/
loop i= 1 to 5. /*Start iterative sweep operation on M from column 1 to column 5*/
-compute M = sweep(M,i).
-print M. /*That's printout we want to trace*/
end loop.
end matrix.

M 在 5 次迭代中的打印输出:

M
     .06660028    -.12645565    -.54275426    -.19692972    -.12195621
     .12645565    3.20350385    -.08946808    2.84946215    1.30671718
     .54275426    -.08946808    7.38023317   -3.51467361   -2.89907198
     .19692972    2.84946215   -3.51467361   13.88671851   10.62244471
     .12195621    1.30671718   -2.89907198   10.62244471    8.41646486

M
     .07159201     .03947417    -.54628594    -.08444957    -.07037464
     .03947417     .31215820    -.02792819     .88948298     .40790248
     .54628594     .02792819    7.37773449   -3.43509328   -2.86257773
     .08444957    -.88948298   -3.43509328   11.35217042    9.46014202
     .07037464    -.40790248   -2.86257773    9.46014202    7.88345168

M
    .112041875    .041542117    .074045215   -.338801789   -.282334825
    .041542117    .312263922    .003785470    .876479537    .397066281
    .074045215    .003785470    .135542964   -.465602725   -.388002270
    .338801789   -.876479537    .465602725   9.752781632   8.127318027
    .282334825   -.397066281    .388002270   8.127318027   6.772765022

M
   .1238115070   .0110941027   .0902197842   .0347389906   .0000000000
   .0110941027   .3910328733  -.0380581058  -.0898696977  -.3333333333
   .0902197842  -.0380581058   .1577710733   .0477405054   .0000000000
   .0347389906  -.0898696977   .0477405054   .1025348498   .8333333333
   .0000000000   .3333333333   .0000000000  -.8333333333   .0000000000

M
   .1238115070   .0110941027   .0902197842   .0347389906   .0000000000
   .0110941027   .3910328733  -.0380581058  -.0898696977   .0000000000
   .0902197842  -.0380581058   .1577710733   .0477405054   .0000000000
   .0347389906  -.0898696977   .0477405054   .1025348498   .0000000000
   .0000000000   .0000000000   .0000000000   .0000000000   .0000000000

请注意,最终第 5 列充满了零。这意味着(据我所知)V5 与前面的一些列线性相关。哪几列?看看第 5 列最后不是全零的迭代 - 迭代 4。我们看到 V5 与 V2 和 V4 相关联,系数为 -.3333 和 .8333:V5 = -.3333*V2+.8333*V4,对应我们对数据所做的工作:V4 = .4*V2+1.2*V5。

这就是我们如何知道哪一列与哪一列线性相关。我没有检查上述方法在更一般的情况下有多大帮助,因为数据中有许多相互依赖的组。不过,在上面的示例中,它似乎很有帮助。

出于诊断目的,我在这里尝试做的是采用矩阵(即转置)并确定矩阵的奇异值(出于诊断目的,您不需要完整的奇异值分解... 然而)。一旦你有了 480 个奇异值,检查其中有多少是“小”的(通常的标准是,如果奇异值小于最大奇异值乘以机器精度,则奇异值是“小”)。如果有任何“小”奇异值,那么是的,你有线性相关性。502×480