Un articolo sulla generazione di matrici di correlazione casuali basate su viti e metodo a cipolla estesa di Lewandowski, Kurowicka e Joe (LKJ), 2009, fornisce un trattamento unificato e l'esposizione dei due metodi efficienti per generare matrici di correlazione casuali. Entrambi i metodi consentono di generare matrici da una distribuzione uniforme in un certo senso definito di seguito, sono semplici da implementare, veloci e hanno un ulteriore vantaggio di avere nomi divertenti.
Una vera matrice simmetrica di dimensioni con quelle sulla diagonale ha d ( d - 1 ) / 2 elementi off-diagonali unici e quindi può essere parametrizzata come punto in R d ( d - 1 ) / 2 . Ogni punto in questo spazio corrisponde a una matrice simmetrica, ma non tutti sono definiti in modo positivo (come devono essere le matrici di correlazione). Le matrici di correlazione formano quindi un sottoinsieme di R d ( d - 1 ) / 2d×dd( d- 1 ) / 2Rd( d- 1 ) / 2Rd( d- 1 ) / 2 (in realtà un sottoinsieme convesso collegato) ed entrambi i metodi possono generare punti da una distribuzione uniforme su questo sottoinsieme.
Fornirò la mia implementazione MATLAB di ciascun metodo e li illustrerò con .d= 100
Metodo di cipolla
Il metodo onion deriva da un altro documento (ref # 3 in LKJ) e possiede il suo nome sul fatto che le matrici di correlazione vengono generate a partire da una matrice e crescendo colonna per colonna e riga per riga. La distribuzione risultante è uniforme. Non capisco davvero la matematica dietro il metodo (e preferisco comunque il secondo metodo), ma ecco il risultato:1 × 1
Qui e sotto il titolo di ogni sottotrama mostra gli autovalori più piccoli e più grandi e il determinante (prodotto di tutti gli autovalori). Ecco il codice:
%// 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
Metodo di cipolla estesa
LKJ modifica leggermente questo metodo, al fine di poter campionare le matrici di correlazione da una distribuzione proporzionale a [ d e tC . Più grande è il η , maggiore sarà il determinante, il che significa che le matrici di correlazione generate si avvicinano sempre più alla matrice dell'identità. Il valore η = 1 corrisponde a una distribuzione uniforme. Nella figura seguente le matrici sono generate con η = 1 , 10 , 100 , 1000 , 10[ d e tC ]η- 1ηη= 1 .η= 1 , 10 , 100 , 1000 , 10000 , 100000
Per qualche motivo per ottenere il determinante dello stesso ordine di grandezza del metodo della cipolla vanigliata, devo mettere e non η = 1 (come sostenuto da LKJ). Non sono sicuro di dove sia l'errore.η=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
Metodo della vite
Il metodo Vine è stato originariamente suggerito da Joe (J in LKJ) e migliorato da LKJ. Mi piace di più, perché è concettualmente più semplice e anche più facile da modificare. L'idea è di generare correlazioni parziali (sono indipendenti e possono avere qualsiasi valore da [ - 1 , 1 ]d(d−1)/2[−1,1]senza alcun vincolo) e poi convertirli in correlazioni grezze tramite una formula ricorsiva. È conveniente organizzare il calcolo in un certo ordine e questo grafico è noto come "vite". È importante sottolineare che, se vengono campionate correlazioni parziali da particolari distribuzioni beta (diverse per celle diverse nella matrice), la matrice risultante verrà distribuita uniformemente. Anche in questo caso, LKJ introduce un ulteriore parametro per campionare da una distribuzione proporzionale a [ d e tη . Il risultato è identico alla cipolla estesa:[detC]η−1
%// 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
Metodo della vite con campionamento manuale di correlazioni parziali
Come si può vedere sopra, la distribuzione uniforme si traduce in matrici di correlazione quasi diagonali. Ma si può facilmente modificare il metodo della vite per avere correlazioni più forti (questo non è descritto nel documento LKJ, ma è semplice): per questo si dovrebbero campionare correlazioni parziali da una distribuzione concentrata attorno a . Di seguito li campiono dalla distribuzione beta (riscalato da [ 0 , 1 ] a [ - 1 , 1 ] ) con α = β = 50 , 20 , 10 , 5 , 2 , 1±1[0,1][−1,1]α=β=50,20,10,5,2,1. Più piccoli sono i parametri della distribuzione beta, più è concentrata vicino ai bordi.
Si noti che in questo caso non è garantito che la distribuzione sia invariante per permutazione, quindi permetto anche casualmente righe e colonne dopo la generazione.
%// 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
Ecco come gli istogrammi degli elementi off-diagonali cercano le matrici sopra (la varianza della distribuzione aumenta monotonicamente):
Aggiornamento: utilizzando fattori casuali
k<dWk×dWW⊤DB=WW⊤+DC=E- 1 / 2B E- 1 / 2EBk = 100 , 50 , 20 , 10 , 5 , 1
E il codice:
%// 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
Ecco il codice di wrapping utilizzato per generare le figure:
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