如何生成存在一些强相关性的大型满秩随机相关性矩阵?


25

我想生成一个n × n大小的随机相关矩阵C,以便存在一些中等强度的相关:n×n

  • n×n大小的平方实对称矩阵,例如n=100
  • 正定的,即所有特征值都是实数和正数;
  • 全职
  • 所有对角线元素等于1 ;
  • 非对角元素应均匀地合理地分布在(1,1)。确切的分布无关紧要,但是我希望有一些适度较大的值(例如10%)的适度较大的值(例如,绝对值为0.5或更高)。基本上我想确保C不是所有的非对角线元素几乎对角线0

有简单的方法吗?

目的是使用此类随机矩阵来对一些使用相关(或协方差)矩阵的算法进行基准测试。


无效的方法

以下是一些我知道的生成随机相关矩阵的方法,但不适用于我:

  1. 生成随机Xs×n大小,中心,规范并形成相关矩阵C=1s1XX。如果s>n,通常将导致所有非对角相关性都在附近0。如果sn,存在一定相关性会很强,但C不会是满秩。

  2. 以下列方式之一生成随机正定矩阵B

    • 生成随机正方形A,使对称正定B=AA

    • 生成随机正方形A,使对称E=A+A,并使其正定通过执行特征分解E=USU和所有负的特征值设置为零:。注意:这将导致秩不足矩阵。B=Umax{S,0}U

    • 生成具有所有正元素的随机正交(例如,通过生成随机平方并进行QR分解或通过Gram-Schmidt过程)和随机对角;形式。d = Q d QQADB=QDQ

    可以容易地将获得的矩阵归一化为对角线都为:,其中D = d i Ç = d - 1 / 2d - 1 / 2BC=D1/2BD1/2是与 B相同对角线的对角矩阵。上面列出的所有三种生成导致非对角元素接近。D=diagBBC 0BC0


更新:旧线程

发布我的问题后,我发现过去几乎有两个重复:

不幸的是,这些线程都没有一个令人满意的答案(直到现在:)


1
您可以通过QR或Gram-Schmidt流程创建随机正交矩阵。那就是“ PCA的特征向量”。在其列中添加比例(变为“加载”)。从这些载荷中获取协方差矩阵。像那样的东西
ttnphns 2014年

1
想象一下,我们要创建一个nXk加载矩阵W,它不是完全随机的,而是我们想要的一个(它将WW'+diag(noise)定义我们要查找的cov矩阵。唯一的任务是校正列归一化的W(即k “本征向量”将变为正交,任何使相关变量(此处为本征向量)不相关的方法都可以做到(这是一个原始想法。)
ttnphns 2014年

1
啊,@ whuber,现在我明白您的意思了。是的,您是对的:如果所有非对角线元素都相同且等于,那么矩阵确实是满秩且是正定的...这当然不是我所想到的:我想分配每个矩阵中的非对角元素应合理地“散布”,而不是矩阵中的分布……ρ
阿米巴说Reinstate Monica 2014年

3
您可能需要研究LKJ发行
shadowtalker,2014年

2
@ttnphns:我想我终于明白你一直都是对的:你的建议是达到目标的最简单方法。我在答案中添加了一个更新,基本上实现了您上面编写的内容。
变形虫说恢复莫妮卡2014年

Answers:


14

其他答案提供了很好的技巧来以各种方式解决我的问题。但是,我发现了一种原则性的方法,我认为它在概念上非常清晰并且易于调整,具有很大的优势。

在该线程中:如何有效地生成随机正-半有限相关矩阵?-我描述并提供了两种生成随机相关矩阵的有效算法的代码。两者都来自Lewandowski,Kurowicka和Joe(2009)的论文,@ ssdecontrol在上面的评论中涉及(非常感谢!)。

请在此处查看我的答案,以获取大量图形,解释和Matlab代码。所谓的“藤蔓”方法允许生成具有任何部分相关分布的随机相关矩阵,并可用于生成具有较大非对角线值的相关矩阵。这是该线程的示例图:

藤蔓法

在子图之间唯一改变的是一个参数,该参数控制偏相关的分布集中在附近。±1

我也复制了代码以在此处生成这些矩阵,以表明它的长度不超过此处建议的其他方法。请查看我的链接答案以获取一些说明。的值betaparam以上针对图分别为(和维数为100)。50,20,10,5,2,1d100

function S = vineBeta(d, betaparam)
    P = zeros(d);           %// storing partial correlations
    S = eye(d);

    for k = 1:d-1
        for i = k+1:d
            P(k,i) = betarnd(betaparam,betaparam); %// sampling from beta
            P(k,i) = (P(k,i)-0.5)*2;     %// linearly shifting to [-1, 1]
            p = P(k,i);
            for l = (k-1):-1:1 %// converting partial correlation to raw correlation
                p = p * sqrt((1-P(l,i)^2)*(1-P(l,k)^2)) + P(l,i)*P(l,k);
            end
            S(k,i) = p;
            S(i,k) = p;
        end
    end

    %// permuting the variables to make the distribution permutation-invariant
    permutation = randperm(d);
    S = S(permutation, permutation);
end

更新:特征值

@psarka询问这些矩阵的特征值。在下图上,我绘制了与上述相同的六个相关矩阵的特征值谱。请注意,它们逐渐减少。相比之下,@ psarka建议的方法通常会生成具有一个较大特征值的相关矩阵,而其余的则相当均匀。

上面矩阵的特征值


更新。真正简单的方法:几个因素

k<nWk×nWWDB=WW+Dk=100,50,20,10,5,1

随机因素的随机相关矩阵

k

这些矩阵的本征谱

这是代码:

d = 100;    %// number of dimensions
k = 5;      %// number of factors

W = randn(d,k);
S = W*W' + diag(rand(1,d));
S = diag(1./sqrt(diag(S))) * S * diag(1./sqrt(diag(S)));

+1。但是,这里只是提醒您有关“因子方法”的最后一部分。严格正确的方法要求的列W是正交的(即它们之间的余弦为0)。W当然,仅生成随机数并不能提供随机数。如果它们不正交-即因素是倾斜(呼叫然后WW_) -因子定理不WW'W_CW_'C被因素之间的“相关性”(余弦)。现在,C=Q'QQ被旋转的非正交旋转矩阵W_=inv(Q)'W(等W=W_Q')。生成一些Q-列ss = 1且矩阵ss =矩阵大小的矩阵。
ttnphns

...典型:W_=inv(Q)'W当然不是W_= W inv(Q)'
ttnphns 2014年

WWW+DW

1
将其转换为R:W = replicate(k, rnorm(d)); S = W%*%t(W) + diag(rnorm(d),nrow=d); S = diag(1/sqrt(diag(S)))%*%S%*%diag(1/sqrt(diag(S)))
Scott Worland

1
@Mihai,要点和您的建议可能是最简单的。您也可以这样做S <- matrix(nearPD(S, corr = TRUE, keepDiag = TRUE)$mat@x,ncol(S),ncol(S))
Scott Worland

7

a

import numpy as np
from random import choice
import matplotlib.pyplot as plt

n = 100
a = 2

A = np.matrix([np.random.randn(n) + np.random.randn(1)*a for i in range(n)])
A = A*np.transpose(A)
D_half = np.diag(np.diag(A)**(-0.5))
C = D_half*A*D_half

vals = list(np.array(C.ravel())[0])
plt.hist(vals, range=(-1,1))
plt.show()
plt.imshow(C, interpolation=None)
plt.show()

分布比较均匀 结果imshow


crsk[a,a]X

是的,您完全正确!(哦,男孩,这的确是愚蠢的:D)。我将随机部分更改为randn(1)* a,现在好多了。
psarka

k

an

这种方法的缺点是所得的相关矩阵具有一个大的特征值,而其余的几乎是均匀的。因此,此过程不会产生“一般”相关矩阵...并不是我在问题中指定了它。但是,在上面的评论中,@ ssdecontrol显然存在从所有相关矩阵中进行采样的方法。这看起来很有趣,但更为复杂。
变形虫说恢复莫妮卡2014年

6

嗯,在用MatMate语言编写示例之后,我看到已经有一个python-answer,这可能是更可取的,因为python被广泛使用。但是,由于您仍然有疑问,我将向您展示我使用Matmate-matrix语言的方法,这也许是更加自我的注释。

方法1
(使用MatMate):

v=12         // 12 variables
f=3          // subset-correlation based on 3 common factors
vg = v / f   // variables per subsets

 // generate hidden factor-matrix
             // randomu(rows,cols ,lowbound, ubound) gives uniform random matrix 
             //    without explicite bounds the default is: randomu(rows,cols,0,100)
L = {   randomu(vg,f)     || randomu(vg,f)/100  || randomu(vg,f)/100 , _
        randomu(vg,f)/100 || randomu(vg,f)      || randomu(vg,f)/100 , _
        randomu(vg,f)/100 || randomu(vg,f)/100  || randomu(vg,f)     }

 // make sure there is itemspecific variance
 // by appending a diagonal-matrix with random positive entries
L = L || mkdiag(randomu(v,1,10,20)) 
  // make covariance and correlation matrix
cov = L *'   // L multiplied  with its transpose
cor = covtocorr(cov)
                   set ccdezweite=3 ccfeldweite=8
                   list cor
cor = 
   1.000,   0.321,   0.919,   0.489,   0.025,   0.019,   0.019,   0.030,   0.025,   0.017,   0.014,   0.014
   0.321,   1.000,   0.540,   0.923,   0.016,   0.015,   0.012,   0.030,   0.033,   0.016,   0.012,   0.015
   0.919,   0.540,   1.000,   0.679,   0.018,   0.014,   0.012,   0.029,   0.028,   0.014,   0.012,   0.012
   0.489,   0.923,   0.679,   1.000,   0.025,   0.022,   0.020,   0.040,   0.031,   0.014,   0.011,   0.014
   0.025,   0.016,   0.018,   0.025,   1.000,   0.815,   0.909,   0.758,   0.038,   0.012,   0.018,   0.014
   0.019,   0.015,   0.014,   0.022,   0.815,   1.000,   0.943,   0.884,   0.035,   0.012,   0.014,   0.012
   0.019,   0.012,   0.012,   0.020,   0.909,   0.943,   1.000,   0.831,   0.036,   0.013,   0.015,   0.010
   0.030,   0.030,   0.029,   0.040,   0.758,   0.884,   0.831,   1.000,   0.041,   0.017,   0.022,   0.020
   0.025,   0.033,   0.028,   0.031,   0.038,   0.035,   0.036,   0.041,   1.000,   0.831,   0.868,   0.780
   0.017,   0.016,   0.014,   0.014,   0.012,   0.012,   0.013,   0.017,   0.831,   1.000,   0.876,   0.848
   0.014,   0.012,   0.012,   0.011,   0.018,   0.014,   0.015,   0.022,   0.868,   0.876,   1.000,   0.904
   0.014,   0.015,   0.012,   0.014,   0.014,   0.012,   0.010,   0.020,   0.780,   0.848,   0.904,   1.000

这里的问题可能是,我们定义了子矩阵块,它们之间具有高相关性,而它们之间的相关性很小,这不是通过编程的方式而是通过常数级联表达式进行的。也许可以在python中更优雅地建模这种方法


方法2(a)
之后,有一种完全不同的方法,在方法中,我们将可能的剩余协方差以100%的随机量填充到因子加载矩阵中。这是在Pari / GP中完成的:

{L = matrix(8,8);  \\ generate an empty factor-loadings-matrix
for(r=1,8, 
   rv=1.0;    \\ remaining variance for variable is 1.0
   for(c=1,8,
        pv=if(c<8,random(100)/100.0,1.0); \\ define randomly part of remaining variance
        cv= pv * rv;  \\ compute current partial variance
        rv = rv - cv;     \\ compute the now remaining variance
        sg = (-1)^(random(100) % 2) ;  \\ also introduce randomly +- signs
        L[r,c] = sg*sqrt(cv) ;  \\ compute factor loading as signed sqrt of cv
       )
     );}

cor = L * L~

并且产生的相关矩阵是

     1.000  -0.7111  -0.08648   -0.7806   0.8394  -0.7674   0.6812    0.2765
   -0.7111    1.000   0.06073    0.7485  -0.7550   0.8052  -0.8273   0.05863
  -0.08648  0.06073     1.000    0.5146  -0.1614   0.1459  -0.4760  -0.01800
   -0.7806   0.7485    0.5146     1.000  -0.8274   0.7644  -0.9373  -0.06388
    0.8394  -0.7550   -0.1614   -0.8274    1.000  -0.5823   0.8065   -0.1929
   -0.7674   0.8052    0.1459    0.7644  -0.5823    1.000  -0.7261   -0.4822
    0.6812  -0.8273   -0.4760   -0.9373   0.8065  -0.7261    1.000   -0.1526
    0.2765  0.05863  -0.01800  -0.06388  -0.1929  -0.4822  -0.1526     1.000

由于因子加载矩阵的累积生成规则,可能会生成具有主要主成分的相关矩阵。另外,最好使方差的最后一部分成为唯一因子,以确保正定性。我将其留在程序中,以保持对一般原理的关注。

一个100x100的关联矩阵具有以下关联频率(四舍五入到1 dec位数)

    e    f            e: entry(rounded) f: frequency
  -----------------------------------------------------
  -1.000, 108.000
  -0.900, 460.000
  -0.800, 582.000
  -0.700, 604.000
  -0.600, 548.000
  -0.500, 540.000
  -0.400, 506.000
  -0.300, 482.000
  -0.200, 488.000
  -0.100, 464.000
   0.000, 434.000
   0.100, 486.000
   0.200, 454.000
   0.300, 468.000
   0.400, 462.000
   0.500, 618.000
   0.600, 556.000
   0.700, 586.000
   0.800, 536.000
   0.900, 420.000
   1.000, 198.000

[更新]。嗯,100x100矩阵的条件不好;即使使用200位数精度,Pari / GP也无法使用polroots(charpoly())函数正确确定特征值。我在loadingsmatrix L上进行了Jacobi旋转到pca形式,并发现大部分极小的特征值,将它们以对数打印到以10为底的位置(大致给出小数点的位置)。从左到右阅读,然后逐行阅读:

log_10(eigenvalues):
   1.684,   1.444,   1.029,   0.818,   0.455,   0.241,   0.117,  -0.423,  -0.664,  -1.040
  -1.647,  -1.799,  -1.959,  -2.298,  -2.729,  -3.059,  -3.497,  -3.833,  -4.014,  -4.467
  -4.992,  -5.396,  -5.511,  -6.366,  -6.615,  -6.834,  -7.535,  -8.138,  -8.263,  -8.766
  -9.082,  -9.482,  -9.940, -10.167, -10.566, -11.110, -11.434, -11.788, -12.079, -12.722
 -13.122, -13.322, -13.444, -13.933, -14.390, -14.614, -15.070, -15.334, -15.904, -16.278
 -16.396, -16.708, -17.022, -17.746, -18.090, -18.358, -18.617, -18.903, -19.186, -19.476
 -19.661, -19.764, -20.342, -20.648, -20.805, -20.922, -21.394, -21.740, -21.991, -22.291
 -22.792, -23.184, -23.680, -24.100, -24.222, -24.631, -24.979, -25.161, -25.282, -26.211
 -27.181, -27.626, -27.861, -28.054, -28.266, -28.369, -29.074, -29.329, -29.539, -29.689
 -30.216, -30.784, -31.269, -31.760, -32.218, -32.446, -32.785, -33.003, -33.448, -34.318

[更新2]
方法2(b)
的改进可能是将特定于项目的方差增加到某个非边际水平,并减少到相当少的公因数(例如,itemnumber的整数平方根):

{  dimr = 100;
   dimc = sqrtint(dimr);        \\ 10 common factors
   L = matrix(dimr,dimr+dimc);  \\ loadings matrix 
                                \\     with dimr itemspecific and 
                                \\          dimc common factors
   for(r=1,dim, 
         vr=1.0;                \\ complete variance per item 
         vu=0.05+random(100)/1000.0;   \\ random variance +0.05
                                       \\ for itemspecific variance
         L[r,r]=sqrt(vu);              \\ itemspecific factor loading  
         vr=vr-vu;
         for(c=1,dimc,
                cv=if(c<dimc,random(100)/100,1.0)*vr;
                vr=vr-cv;
                L[r,dimr+c]=(-1)^(random(100) % 2)*sqrt(cv)
             )
        );}

   cov=L*L~
   cp=charpoly(cov)   \\ does not work even with 200 digits precision
   pr=polroots(cp)    \\ spurious negative and complex eigenvalues...

结果的结构

就相关分布而言:图片

仍然相似(PariGP也令人讨厌的不可分解性),但是当通过loadsmatrix的雅各比旋转发现特征值时,它具有更好的结构,对于一个新计算的示例,我得到的特征值为

log_10(eigenvalues):
   1.677,   1.326,   1.063,   0.754,   0.415,   0.116,  -0.262,  -0.516,  -0.587,  -0.783
  -0.835,  -0.844,  -0.851,  -0.854,  -0.858,  -0.862,  -0.862,  -0.868,  -0.872,  -0.873
  -0.878,  -0.882,  -0.884,  -0.890,  -0.895,  -0.896,  -0.896,  -0.898,  -0.902,  -0.904
  -0.904,  -0.909,  -0.911,  -0.914,  -0.920,  -0.923,  -0.925,  -0.927,  -0.931,  -0.935
  -0.939,  -0.939,  -0.943,  -0.948,  -0.951,  -0.955,  -0.956,  -0.960,  -0.967,  -0.969
  -0.973,  -0.981,  -0.986,  -0.989,  -0.997,  -1.003,  -1.005,  -1.011,  -1.014,  -1.019
  -1.022,  -1.024,  -1.031,  -1.038,  -1.040,  -1.048,  -1.051,  -1.061,  -1.064,  -1.068
  -1.070,  -1.074,  -1.092,  -1.092,  -1.108,  -1.113,  -1.120,  -1.134,  -1.139,  -1.147
  -1.150,  -1.155,  -1.158,  -1.166,  -1.171,  -1.175,  -1.184,  -1.184,  -1.192,  -1.196
  -1.200,  -1.220,  -1.237,  -1.245,  -1.252,  -1.262,  -1.269,  -1.282,  -1.287,  -1.290

非常感谢!非常有趣,但是会花一些时间来消化...
变形虫说2014年

我仍然必须仔细地回答您的问题,但是与此同时,我读了一篇有关对随机相关矩阵进行采样的论文,并且那里的一种方法可以用来精确地完成我需要的工作。我在这里发布了答案,您可能有兴趣看看!它链接到我在另一个线程中写的更详细的答案。
变形虫说恢复莫妮卡2014年

@amoeba:很高兴您找到了对您有用的东西!这是一个有趣的问题,我待会儿会再说一遍,也许会根据您所研究的论文来改进/调整MatMate程序(并使其成为子例程)。
Gottfried Helms 2014年

2

ABλA+(1λ)Bλ

ABCλAA+λBB+λCCλ=1λ0


AB

嗯,但是通过这样的算法以及定义正定相关矩阵多边形的“顶点”(即矩阵)中的适当多样性,您可以使用拒绝采样来获取特征值的分布,条目的均匀性,等你想要的。但是,我不清楚良好的基础是什么。听起来像是谁研究抽象代数最近比我的人一个问题
安德鲁中号

再次,您好,我读了一篇有关抽样随机相关矩阵的论文,其中的一种方法可以用来精确地完成我需要的工作。我在这里发布了答案,您可能有兴趣看看!它链接到我在另一个线程中写的更详细的答案。
变形虫说恢复莫妮卡2014年

2

R有一个包(clusterGeneration),可在以下方式中实现该方法:

例:

> (cormat10 = clusterGeneration::rcorrmatrix(10, alphad = 1/100000000000000))
        [,1]   [,2]    [,3]     [,4]     [,5]   [,6]   [,7]    [,8]     [,9]   [,10]
 [1,]  1.000  0.344 -0.1406 -0.65786 -0.19411  0.246  0.688 -0.6146  0.36971 -0.1052
 [2,]  0.344  1.000 -0.4256 -0.35512  0.15973  0.192  0.340 -0.4907 -0.30539 -0.6104
 [3,] -0.141 -0.426  1.0000  0.01775 -0.61507 -0.485 -0.273  0.3492 -0.30284  0.1647
 [4,] -0.658 -0.355  0.0178  1.00000  0.00528 -0.335 -0.124  0.5256 -0.00583 -0.0737
 [5,] -0.194  0.160 -0.6151  0.00528  1.00000  0.273 -0.350 -0.0785  0.08285  0.0985
 [6,]  0.246  0.192 -0.4847 -0.33531  0.27342  1.000  0.278 -0.2220 -0.11010  0.0720
 [7,]  0.688  0.340 -0.2734 -0.12363 -0.34972  0.278  1.000 -0.6409  0.40314 -0.2800
 [8,] -0.615 -0.491  0.3492  0.52557 -0.07852 -0.222 -0.641  1.0000 -0.50796  0.1461
 [9,]  0.370 -0.305 -0.3028 -0.00583  0.08285 -0.110  0.403 -0.5080  1.00000  0.3219
[10,] -0.105 -0.610  0.1647 -0.07373  0.09847  0.072 -0.280  0.1461  0.32185  1.0000
> cormat10[lower.tri(cormat10)] %>% psych::describe()
   vars  n  mean   sd median trimmed mad   min  max range skew kurtosis   se
X1    1 45 -0.07 0.35  -0.08   -0.07 0.4 -0.66 0.69  1.35 0.03       -1 0.05

不幸的是,似乎不可能模拟遵循均匀分布的相关性。当alphad设置为非常小的值时,似乎会产生更强的相关性,但是即使在处1/100000000000000,相关性范围也只会上升到大约1.40。

尽管如此,我希望这可能对某人有用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.