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
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[ d e tC ]η- 1ηη= 1 .η= 1 , 10 , 100 , 1000 , 10000 , 100000
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η= 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:[ 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étodo Vine com amostragem manual de correlações parciais
± 1[ 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.
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):
Atualização: usando fatores aleatórios
k < dWk × dW W⊤DB = W W⊤+ DC = E- 1 / 2B E- 1 / 2EBk = 100 , 50 , 20 , 10 , 5 , 1
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