Un documento que genera matrices de correlación aleatorias basadas en vides y método de cebolla extendida por Lewandowski, Kurowicka y Joe (LKJ), 2009, proporciona un tratamiento unificado y una exposición de los dos métodos eficientes de generar matrices de correlación aleatorias. Ambos métodos permiten generar matrices a partir de una distribución uniforme en un cierto sentido preciso definido a continuación, son fáciles de implementar, rápidos y tienen la ventaja adicional de tener nombres divertidos.
Una matriz simétrica real de tamaño con unos en la diagonal tiene d ( d - 1 ) / 2 elementos únicos fuera de la diagonal y, por lo tanto, se puede parametrizar como un punto en R d ( d - 1 ) / 2 . Cada punto en este espacio corresponde a una matriz simétrica, pero no todos son positivos definidos (como deben ser las matrices de correlación). Las matrices de correlación, por lo tanto, forman un subconjunto de R d ( d - 1 ) / 2d×dd(d−1)/2Rd(d−1)/2Rd(d−1)/2 (en realidad, un subconjunto convexo conectado), y ambos métodos pueden generar puntos a partir de una distribución uniforme sobre este subconjunto.
Proporcionaré mi propia implementación de MATLAB de cada método y los ilustraré con .d=100
Método de cebolla
El método de la cebolla proviene de otro artículo (ref. # 3 en LKJ) y su nombre se debe al hecho de que las matrices de correlación se generan comenzando con una matriz y creciendo columna por columna y fila por fila. La distribución resultante es uniforme. Realmente no entiendo las matemáticas detrás del método (y prefiero el segundo método de todos modos), pero aquí está el resultado:1×1
Aquí y debajo, el título de cada subtrama muestra los valores propios más pequeños y más grandes, y el determinante (producto de todos los valores propios). Aquí está el 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 de cebolla extendida
LKJ modifica ligeramente este método para poder muestrear matrices de correlación de una distribución proporcional a [ d e tC . Cuanto mayor sea η , mayor será el determinante, lo que significa que las matrices de correlación generadas se acercarán cada vez más a la matriz de identidad. El valor η = 1 corresponde a una distribución uniforme. En la figura siguiente, las matrices se generan con η = 1 , 10 , 100 , 1000 , 10[detC]η−1ηη=1 .η=1,10,100,1000,10000,100000
Por alguna razón para obtener el determinante del mismo orden de magnitud que en el método de la cebolla de vainilla, necesito poner y no η = 1 (como afirma LKJ). No estoy seguro de dónde está el error.η=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 la vid
El método Vine fue originalmente sugerido por Joe (J en LKJ) y mejorado por LKJ. Me gusta más, porque es conceptualmente más fácil y también más fácil de modificar. La idea es generar correlaciones parciales (son independientes y pueden tener cualquier valor de [ - 1 , 1 ]d(d−1)/2[−1,1]sin restricciones) y luego conviértalos en correlaciones crudas a través de una fórmula recursiva. Es conveniente organizar el cálculo en un cierto orden, y este gráfico se conoce como "vid". Es importante destacar que si se muestrean correlaciones parciales de distribuciones beta particulares (diferentes para diferentes células en la matriz), la matriz resultante se distribuirá uniformemente. Aquí nuevamente, LKJ introduce un parámetro adicional para muestrear desde una distribución proporcional a [ d e tη . El resultado es idéntico a la cebolla extendida:[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
Método de vid con muestreo manual de correlaciones parciales.
±1[0,1][−1,1]α=β=50,20,10,5,2,1. Cuanto más pequeños son los parámetros de la distribución beta, más se concentra cerca de los bordes.
Tenga en cuenta que en este caso no se garantiza que la distribución sea invariante de permutación, por lo que adicionalmente permuto aleatoriamente filas y columnas después de la generación.
%// 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
Así es como los histogramas de los elementos fuera de la diagonal buscan las matrices anteriores (la variación de la distribución aumenta monotónicamente):
Actualización: utilizando factores aleatorios
k<dWk×dWW⊤DB=WW⊤+DC=E−1/2BE−1/2EBk=100,50,20,10,5,1
Y el codigo:
%// 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
Aquí está el código de ajuste utilizado para generar las 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