Como gerar eficientemente matrizes de correlação aleatória positiva-semidefinida?

38

Gostaria de poder gerar com eficiência matrizes de correlação semidefinido positivo (PSD). Meu método diminui drasticamente à medida que aumenta o tamanho das matrizes a serem geradas.

  1. Você poderia sugerir soluções eficientes? Se você conhece algum exemplo no Matlab, ficaria muito grato.
  2. Ao gerar uma matriz de correlação do PSD, como você selecionaria os parâmetros para descrever as matrizes a serem geradas? Uma correlação média, desvio padrão de correlações, autovalores?
Eduardas
fonte

Respostas:

16

Você pode fazer isso ao contrário: toda matriz (o conjunto de todas as matrizes simétricas p × p PSD) pode ser decomposta comoCR++pp×p

que O é uma matriz ortonormalC=OTDOO

Para obter , geram primeiro uma base aleatória ( v 1 , . . . , V p ) (onde v i são vectores aleatórios, tipicamente em ( - 1 , 1 ) ). De lá, use o processo ortogonalização Gram-Schmidt para obter ( u 1 , . . . . , U p ) = OO(v1,...,vp)vEu(-1,1)(você1,....,vocêp)=O

possui vários pacotes que podem realizar a ortogonalização GS de uma base aleatória de forma eficiente, ou seja, mesmo para grandes dimensões, por exemplo, o pacote 'distante'. Embora você encontre o algoritmo GS no wiki, provavelmente é melhor não reinventar a roda e fazer uma implementação do matlab (certamente existe uma, eu simplesmente não posso recomendar nenhuma).R

Finalmente, é um matrizes diagonais cujos elementos são todos positivos (isto é, de novo, fácil de gerar: gerar p números aleatórios, quadrado-los, classificá-los e colocá-los até a diagonal de uma identidade p por p matriz).Dppp

user603
fonte
3
(1) Observe que o resultante não será uma matriz de correlação (conforme solicitado pelo OP), porque não terá matrizes na diagonal. Claro que pode ser adaptada a ter os sobre a diagonal, definindo-o E - 1 / 2 C E - 1 / 2 , onde E é uma matriz diagonal com o mesmo diagonal como C . (2) Se não me engano, isso resultará em matrizes de correlação, onde todos os elementos fora da diagonal estão concentrados em torno de 0 , portanto, não há flexibilidade que o OP estava procurando (o OP queria poder definir "uma correlação média , desvio padrão de correlações, autovalores "CE1/2CE1/2EC0 0)
ameba diz Reinstate Monica
@amoeba: Vou abordar (2) uma vez que, como você aponta, a solução para (1) é trivial. A caracterização de um número da 'forma' (a relação entre os elementos diagonal de entrada e saída) de uma matriz de PSD (e, portanto, uma matriz de covariância e também uma matriz de correlação) é seu número de condição. E, o método descrito acima permite controle total sobre ele. A 'concentração dos elementos fora da diagonal em torno de 0' não é uma característica do método usado para gerar matrizes de PSD, mas sim uma consequência das restrições necessárias para garantir que a matriz seja PSD e o fato de ser grande. p
user603
Você está dizendo que todas as grandes matrizes de PSD têm elementos fora da diagonal próximos de zero? Eu discordo, não é assim. Verifique minha resposta aqui para ver alguns exemplos: Como gerar uma matriz de correlação aleatória que tem aproximadamente entradas normalmente fora da diagonal distribuídas com determinado desvio padrão? Mas pode-se ver diretamente que não é esse o caso, porque uma matriz quadrada com todas na diagonal e um valor fixo qualquer lugar fora da diagonal é PSD e ρ pode ser arbitrariamente grande (mas é claro abaixo de 1 ). ρρ1
Ameba diz Reinstate Monica
@amoeba: então eu estava errado em supor que, por necessidade, a diagonal off de grandes matrizes de correlação, quando elas podem ser positivas e negativas, seja próxima de 0. Obrigado pelo exemplo esclarecedor.
user603
1
Eu li um artigo muito bom sobre a geração de matrizes de correlação aleatória e forneci minha própria resposta aqui (assim como outra resposta nesse segmento vinculado). Eu acho que você pode achar interessante.
Ameba diz Reinstate Monica
27

Um artigo Gerando matrizes de correlação aleatória com base em videiras e método de cebola estendida por Lewandowski, Kurowicka e Joe (LKJ), 2009, fornece um tratamento unificado e exposição dos dois métodos eficientes de gerar matrizes de correlação aleatória. Ambos os métodos permitem gerar matrizes a partir de uma distribuição uniforme em um certo sentido preciso definido abaixo, são simples de implementar, rápidos e têm uma vantagem adicional de ter nomes divertidos.

Uma matriz simétrica real do tamanho com aqueles na diagonal tem d ( d - 1 ) / 2 elementos fora da diagonal exclusivos e assim pode ser parametrizada como um ponto em R d ( d - 1 ) / 2 . Cada ponto neste espaço corresponde a uma matriz simétrica, mas nem todos são positivos-definidos (como as matrizes de correlação precisam ser). Matrizes de correlação, portanto, formam um subconjunto de R d ( d - 1 ) / 2d×dd(d-1)/2Rd(d-1)/2Rd(d-1)/2 (na verdade, um subconjunto convexo conectado) e os dois métodos podem gerar pontos a partir de uma distribuição uniforme nesse subconjunto.

Fornecerei minha própria implementação MATLAB de cada método e ilustrarei com .d=100


Método de cebola

O método cebola vem de outro papel (ref # 3 em LKJ) e possui o seu nome ao facto das matrizes de correlação são gerados a partir de matriz e o seu cultivo em coluna por coluna e linha por linha. A distribuição resultante é uniforme. Eu realmente não entendo a matemática por trás do método (e prefiro o segundo método de qualquer maneira), mas aqui está o resultado:1×1

Método de cebola

Aqui e abaixo, o título de cada subparcela mostra os autovalores menores e maiores e o determinante (produto de todos os autovalores). Aqui está o código:

%// ONION METHOD to generate random correlation matrices distributed randomly
function S = onion(d)
    S = 1;
    for k = 2:d
        y = betarnd((k-1)/2, (d-k)/2); %// sampling from beta distribution
        r = sqrt(y);
        theta = randn(k-1,1);
        theta = theta/norm(theta);
        w = r*theta;
        [U,E] = eig(S);
        R = U*E.^(1/2)*U';             %// R is a square root of S
        q = R*w;
        S = [S q; q' 1];               %// increasing the matrix size
    end
end

Método estendido de cebola

LKJ modifica este método levemente, para poder amostrar as matrizes de correlação de uma distribuição proporcional a [ d e tC . Quanto maior o η , maior será o determinante, o que significa que as matrizes de correlação geradas se aproximam cada vez mais da matriz de identidade. O valor η = 1 corresponde à distribuição uniforme. Na figura abaixo, as matrizes são geradas com η = 1 , 10 , 100 , 1000 , 10[detC]η-1ηη=1 .η=1,10,100,1000,10000,100000

Método estendido de cebola

Por alguma razão, para obter o determinante da mesma ordem de grandeza que no método da cebola com baunilha, preciso colocar e não η = 1 (conforme reivindicado por LKJ). Não tenho certeza de onde está o erro.η=0 0η=1

%// EXTENDED ONION METHOD to generate random correlation matrices
%// distributed ~ det(S)^eta [or maybe det(S)^(eta-1), not sure]
function S = extendedOnion(d, eta)
    beta = eta + (d-2)/2;
    u = betarnd(beta, beta);
    r12 = 2*u - 1;
    S = [1 r12; r12 1];  

    for k = 3:d
        beta = beta - 1/2;
        y = betarnd((k-1)/2, beta);
        r = sqrt(y);
        theta = randn(k-1,1);
        theta = theta/norm(theta);
        w = r*theta;
        [U,E] = eig(S);
        R = U*E.^(1/2)*U';
        q = R*w;
        S = [S q; q' 1];
    end
end

Método de videira

O método Vine foi originalmente sugerido por Joe (J em LKJ) e aprimorado por LKJ. Eu gosto mais, porque é conceitualmente mais fácil e mais fácil de modificar. A idéia é gerar correlações parciais (elas são independentes e podem ter valores de [ - 1 , 1 ]d(d-1)/2[-1,1]sem restrições) e depois os converta em correlações brutas por meio de uma fórmula recursiva. É conveniente organizar o cálculo em uma determinada ordem, e este gráfico é conhecido como "videira". É importante ressaltar que, se forem amostradas correlações parciais de distribuições beta específicas (diferentes para células diferentes na matriz), a matriz resultante será distribuída uniformemente. Aqui, novamente, LKJ introduz um parâmetro adicional para amostrar a partir de uma distribuição proporcional a [ d e tη . O resultado é idêntico à cebola estendida:[detC]η-1

Método de videira

%// VINE METHOD to generate random correlation matrices
%// distributed ~ det(S)^eta [or maybe det(S)^(eta-1), not sure]
function S = vine(d, eta)
    beta = eta + (d-1)/2;   
    P = zeros(d);           %// storing partial correlations
    S = eye(d);

    for k = 1:d-1
        beta = beta - 1/2;
        for i = k+1:d
            P(k,i) = betarnd(beta,beta); %// 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
end

Método Vine com amostragem manual de correlações parciais

±1[0 0,1][-1,1]α=β=50.,20,10,5,2,1. Quanto menores os parâmetros da distribuição beta, mais ela se concentra nas bordas.

Método Vine com amostragem manual

Observe que, neste caso, a distribuição não é garantida como invariante de permutação, portanto, adicionalmente permito aleatoriamente linhas e colunas após a geração.

%// VINE METHOD to generate random correlation matrices
%// with all partial correlations distributed ~ beta(betaparam,betaparam)
%// rescaled to [-1, 1]
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

Aqui está como os histogramas dos elementos fora da diagonal procuram as matrizes acima (a variação da distribuição aumenta monotonicamente):

Elementos fora da diagonal


Atualização: usando fatores aleatórios

k<dWk×dWWDB=WW+DC=E-1/2BE-1/2EBk=100,50.,20,10,5,1

matrizes de correlação aleatória a partir de fatores aleatórios

E o código:

%// FACTOR method
function S = factor(d,k)
    W = randn(d,k);
    S = W*W' + diag(rand(1,d));
    S = diag(1./sqrt(diag(S))) * S * diag(1./sqrt(diag(S)));
end

Aqui está o código de quebra automática usado para gerar as figuras:

d = 100; %// size of the correlation matrix

figure('Position', [100 100 1100 600])
for repetition = 1:6
    S = onion(d);

    %// etas = [1 10 100 1000 1e+4 1e+5];
    %// S = extendedOnion(d, etas(repetition));

    %// S = vine(d, etas(repetition));

    %// betaparams = [50 20 10 5 2 1];
    %// S = vineBeta(d, betaparams(repetition));

    subplot(2,3,repetition)

    %// use this to plot colormaps of S
    imagesc(S, [-1 1])
    axis square
    title(['Eigs: ' num2str(min(eig(S)),2) '...' num2str(max(eig(S)),2) ', det=' num2str(det(S),2)])

    %// use this to plot histograms of the off-diagonal elements
    %// offd = S(logical(ones(size(S))-eye(size(S))));
    %// hist(offd)
    %// xlim([-1 1])
end
ameba diz Restabelecer Monica
fonte
2
Este é um resumo fantástico, estou feliz por ter dito alguma coisa!
shadowtalker
Quando traduzi o código matlab da matriz de correlação baseada em videira para R e o testei, a densidade das correlações na coluna 1 sempre foi diferente das colunas posteriores. Talvez eu tenha traduzido algo incorretamente, mas talvez essa nota ajude alguém.
Charlie
3
Para usuários R, a função rcorrmatrix no pacote clusterGeneration (escrita por W Qui e H. Joe) implementa o método vine.
RNM 12/07
15

UMAUMATUMAyT(UMATUMA)y0 0yyT(UMATUMA)y=(UMAy)TUMAy=||UMAy||o que não é negativo. Então, no Matlab, tente

A = randn(m,n);   %here n is the desired size of the final matrix, and m > n
X = A' * A;

Dependendo do aplicativo, isso pode não fornecer a distribuição dos valores próprios que você deseja; A resposta de Kwak é muito melhor nesse sentido. Os valores próprios Xproduzidos por esse trecho de código devem seguir a distribuição Marchenko-Pastur.

Para simular as matrizes de correlação de ações, por exemplo, convém uma abordagem ligeiramente diferente:

k = 7;      % # of latent dimensions;
n = 100;    % # of stocks;
A = 0.01 * randn(k,n);  % 'hedgeable risk'
D = diag(0.001 * randn(n,1));   % 'idiosyncratic risk'
X = A'*A + D;
ascii_hist(eig(X));    % this is my own function, you do a hist(eig(X));
-Inf <= x <  -0.001 : **************** (17)
-0.001 <= x <   0.001 : ************************************************** (53)
 0.001 <= x <   0.002 : ******************** (21)
 0.002 <= x <   0.004 : ** (2)
 0.004 <= x <   0.005 :  (0)
 0.005 <= x <   0.007 : * (1)
 0.007 <= x <   0.008 : * (1)
 0.008 <= x <   0.009 : *** (3)
 0.009 <= x <   0.011 : * (1)
 0.011 <= x <     Inf : * (1)
shabbychef
fonte
1
você estaria disposto a compartilhar sua função ascii_hist por acaso?
btown
@btown a margem é muito pequena para contê-la!
shabbychef
1
yT(UMATUMA)y=(UMAy)TUMAy=||UMAy||
8

Como variação da resposta do kwak: gere uma matriz diagonal D com autovalores não negativos aleatórios de uma distribuição de sua escolha e, em seguida, execute uma transformação de similaridade UMA=QDQT com Quma matriz ortogonal pseudo-aleatória distribuída por Haar .

JM não é estatístico
fonte
M.: Boa referência: esta parece ser a solução mais eficiente (assintoticamente).
whuber
3
@whuber: Heh, eu peguei no Golub e Van Loan (é claro); Eu uso isso o tempo todo para ajudar na geração de matrizes de teste para rotinas de autovalor / valor singular de teste de estresse. Como pode ser visto no artigo, é essencialmente equivalente à decomposição de QR de uma matriz aleatória como o que o kwak sugeriu, exceto que é feito com mais eficiência. Existe uma implementação MATLAB disso na Text Matrix Toolbox da Higham, BTW.
JM não é estatístico
M .:: Obrigado pela implementação do matlab. Você por acaso conheceria um gerador de matriz pseudo-aleatória Haar em R?
user603
@kwak: Não faço ideia, mas se ainda não há implementação, não deve ser muito difícil traduzir o código do MATLAB para R (posso tentar criar um se não houver); o único pré-requisito é um gerador decente para variáveis ​​normais pseudo-aleatórias, o que tenho certeza que R possui.
JM não é estatístico
M.:> sim, eu provavelmente vou traduzir por mim mesmo. Obrigado pelos links, Melhor.
user603
4

Você não especificou uma distribuição para as matrizes. Dois comuns são as distribuições Wishart e inversa Wishart. A decomposição de Bartlett fornece uma fatoração de Cholesky de uma matriz Wishart aleatória (que também pode ser resolvida com eficiência para obter uma matriz Wishart inversa aleatória).

De fato, o espaço de Cholesky é uma maneira conveniente de gerar outros tipos de matrizes aleatórias de PSD, pois você só precisa garantir que a diagonal não seja negativa.

Simon Byrne
fonte
> Não aleatório: duas matrizes geradas a partir do mesmo Whishard não serão independentes uma da outra. Se você planeja mudar o Whishart a cada geração, como pretende gerar esses Whishart em primeiro lugar?
user603
@kwak: Não entendi sua pergunta: a decomposição de Bartlett fornecerá empates independentes da mesma distribuição do Wishart.
Simon Byrne
> Deixe-me reformular isso, de onde você obtém a matriz de escala da sua distribuição whishart?
user603
1
@kwak: é um parâmetro da distribuição, e assim é fixo. Você o seleciona no início, com base nas características desejadas da sua distribuição (como a média).
Simon Byrne
3

O método mais simples é o descrito acima, que é uma simulação de um conjunto de dados aleatório e o cálculo do Gramian . Uma palavra de cautela: A matriz resultante não será uniformemente aleatória, pois sua decomposição, por exemplo,vocêTSvocêterá rotações não distribuídas de acordo com a medida de Haar. Se você quiser ter matrizes PSD "distribuídas uniformemente", poderá usar qualquer uma das abordagens descritas aqui .

gappy
fonte
Se as entradas são geradas a partir de uma distribuição Normal em vez de uniforme, a decomposição mencionada deve ser SO (n) invariável (e, portanto, equidistribuída em relação à medida de Haar).
whuber
Interessante. Você pode fornecer uma referência para isso?
quer
1
> o problema com esse método é que você não pode controlar a proporção do menor para o maior autovalor (e acho que, à medida que o tamanho do seu conjunto de dados gerado aleatoriamente chegar ao infinito, essa proporção convergirá para 1).
user603
1

Se você deseja ter mais controle sobre sua matriz PSD simétrica gerada, por exemplo, gerar um conjunto de dados de validação sintético, você tem vários parâmetros disponíveis. Uma matriz PSD simétrica corresponde a uma hiperelipse no espaço N-dimensional, com todos os graus de liberdade relacionados:

  1. Rotações.
  2. Comprimentos de eixos.

Portanto, para uma matriz bidimensional (isto é, elipse 2d), você terá 1 rotação + 2 eixos = 3 parâmetros.

Se as rotações lembram matrizes ortogonais, é um trem correto, pois a construção é novamente Σ=ODOTcom Σ sendo a matriz Sym.PSD produzida, O a matriz de rotação (ortogonal) e Da matriz diagonal, cujos elementos diagonais controlarão o comprimento dos eixos da elipse.

O código Matlab a seguir plota 16 conjuntos de dados distribuídos gaussianos bidimensionais com base em Σ, com um ângulo crescente. O código para geração aleatória de parâmetros está nos comentários.

figure;
mu = [0,0];
for i=1:16
    subplot(4,4,i)
    theta = (i/16)*2*pi;   % theta = rand*2*pi;
    U=[cos(theta), -sin(theta); sin(theta) cos(theta)];
    % The diagonal's elements control the lengths of the axes
    D = [10, 0; 0, 1]; % D = diag(rand(2,1));    
    sigma = U*D*U';
    data = mvnrnd(mu,sigma,1000);
    plot(data(:,1),data(:,2),'+'); axis([-6 6 -6 6]); hold on;
end

Para mais dimensões, a matriz Diagonal é direta (como acima), e a você deve derivar da multiplicação das matrizes de rotação.

PeriRamm
fonte
0

Uma abordagem barata e alegre que usei para testar é gerar m N (0,1) n-vetores V [k] e usar P = d * I + Soma {V [k] * V [k] '} como uma matriz nxn psd. Com m <n, isso será singular para d = 0 e, para d pequeno, terá um número de condição alto.


fonte
2
> o problema com esse método é que você não pode controlar a proporção do menor para o maior autovalor (e acho que, à medida que o tamanho do seu conjunto de dados gerado aleatoriamente chegar ao infinito, essa proporção convergirá para 1).
user603
> além disso, o método não é muito eficiente (do ponto de vista computacional)
user603
1
Sua "matriz aleatória" é uma estrutura especialmente chamada de "matriz diagonal mais rank-1" (matriz DR1), portanto, não é realmente uma boa matriz aleatória representativa.
JM não é estatístico