Un article Génération de matrices de corrélation aléatoire à base de vignes et de méthode d'oignon étendu par Lewandowski, Kurowicka et Joe (LKJ), 2009, fournit un traitement et une présentation unifiés des deux méthodes efficaces de génération de matrices de corrélation aléatoire. Les deux méthodes permettent de générer des matrices à partir d'une distribution uniforme dans un certain sens défini ci-dessous, sont simples à mettre en œuvre, rapides et présentent l'avantage supplémentaire d'avoir des noms amusants.
Une matrice symétrique réelle de taille avec des unités sur la diagonale a d ( d - 1 ) / 2 éléments uniques hors diagonale et peut donc être paramétrée comme un point dans R d ( d - 1 ) / 2 . Chaque point de cet espace correspond à une matrice symétrique, mais tous ne sont pas définis positivement (comme doivent l'être les matrices de corrélation). Les matrices de corrélation forment donc un sous-ensemble de R d ( d - 1 ) / 2ré× dré( d- 1 ) / 2Rré( d- 1 ) / 2Rré( d- 1 ) / 2 (en réalité un sous-ensemble convexe connecté) et les deux méthodes peuvent générer des points à partir d’une distribution uniforme sur ce sous-ensemble.
Je vais fournir ma propre implémentation MATLAB de chaque méthode et les illustrer avec .ré= 100
Méthode de l'oignon
La méthode de l'oignon provient d'un autre document (référence n ° 3 dans LKJ) et tire son nom du fait que les matrices de corrélation sont générées en commençant par la matrice et en le développant colonne par colonne et ligne par ligne. La distribution résultante est uniforme. Je ne comprends pas vraiment le calcul derrière la méthode (et préfère la deuxième méthode de toute façon), mais voici le résultat:1 × 1
Ci-dessous et en dessous, le titre de chaque sous-parcelle indique les valeurs propres les plus petites et les plus grandes, ainsi que le déterminant (produit de toutes les valeurs propres). Voici le code:
%// 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éthode de l'oignon étendu
Les LKJ modifient légèrement cette méthode afin de pouvoir échantillonner les matrices de corrélation partir d’une distribution proportionnelle à [ d e tC . Plus le η est grand , plus le déterminant sera grand, ce qui signifie que les matrices de corrélation générées s'approcheront de plus en plus de la matrice d'identité. La valeur η = 1 correspond à une distribution uniforme. Sur la figure ci-dessous, les matrices sont générées avec η = 1 , 10 , 100 , 1000 , 10[ d e tC ]η- 1ηη= 1 .η= 1 , 10 , 100 , 1000 , 10000 , 100000
Pour une raison quelconque d'obtenir un déterminant du même ordre de grandeur que dans la méthode de l'oignon à la vanille, je dois mettre et non pas η = 1 (comme l'affirme LKJ). Je ne sais pas où est l'erreur.η= 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éthode de la vigne
La méthode de la vigne a été proposée à l'origine par Joe (J en LKJ) et améliorée par LKJ. Je l’aime plus, parce que c’est conceptuellement plus facile et aussi plus facile à modifier. L'idée est de générer corrélations partielles (elles sont indépendantes et peuvent avoir n'importe quelle valeur de [ - 1 , 1 ]ré( d- 1 ) / 2[ - 1 , 1 ]sans contrainte) puis convertissez-les en corrélations brutes via une formule récursive. Il est pratique d'organiser le calcul dans un certain ordre. Ce graphe est appelé "vigne". De manière importante, si des corrélations partielles sont échantillonnées à partir de distributions bêta particulières (différentes pour différentes cellules de la matrice), la matrice résultante sera distribuée de manière uniforme. Là encore, LKJ introduit un paramètre supplémentaire à échantillonner à partir d’une distribution proportionnelle à [ d e tη . Le résultat est identique à l'oignon étendu:[ d e tC ]η- 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
Méthode de la vigne avec échantillonnage manuel des corrélations partielles
± 1[ 0 , 1 ][ - 1 , 1 ]α = β= 50 , 20 , 10 , 5 , 2 , 1. Plus les paramètres de la distribution bêta sont petits, plus elle est concentrée près des bords.
Notez que dans ce cas, la distribution n'est pas garantie d'être invariante à la permutation, aussi permutez-vous de manière aléatoire de manière aléatoire les lignes et les colonnes après la génération.
%// 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
Voici comment les histogrammes des éléments hors diagonale recherchent les matrices ci-dessus (la variance de la distribution augmente de façon monotone):
Mise à jour: utilisation de facteurs aléatoires
k < dWk × dW W⊤réB = W W⊤+ DC = E- 1 / deuxB E- 1 / deuxEBk = 100 , 50 , 20 , 10 , 5 , 1
Et le code:
%// 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
Voici le code d'emballage utilisé pour générer les chiffres:
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