A paper Generating random correlation matrices based on vines and extended
onion method by Lewandowski, Kurowicka, and Joe (LKJ), 2009, provides a unified treatment and exposition of the two efficient methods of generating random correlation matrices. Both methods allow to generate matrices from a uniform distribution in a certain precise sense defined below, are simple to implement, fast, and have an added advantage of having amusing names.
A real symmetric matrix of $d \times d$ size with ones on the diagonal has $d(d-1)/2$ unique off-diagonal elements and so can be parametrized as a point in $\mathbb R^{d(d-1)/2}$. Each point in this space corresponds to a symmetric matrix, but not all of them are positive-definite (as correlation matrices have to be). Correlation matrices therefore form a subset of $\mathbb R^{d(d-1)/2}$ (actually a connected convex subset), and both methods can generate points from a uniform distribution over this subset.
I will provide my own MATLAB implementation of each method and illustrate them with $d=100$.
Onion method
The onion method comes from another paper (ref #3 in LKJ) and owns its name to the fact the correlation matrices are generated starting with $1\times 1$ matrix and growing it column by column and row by row. Resulting distribution is uniform. I don't really understand the math behind the method (and prefer the second method anyway), but here is the result:
Here and below the title of each subplot shows the smallest and the largest eigenvalues, and the determinant (product of all eigenvalues). Here is the 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
Extended onion method
LKJ modify this method slightly, in order to be able to sample correlation matrices $\mathbf C$ from a distribution proportional to $[\mathrm{det}\:\mathbf C]^{\eta-1}$. The larger the $\eta$, the larger will be the determinant, meaning that generated correlation matrices will more and more approach the identity matrix. The value $\eta=1$ corresponds to uniform distribution. On the figure below the matrices are generated with $\eta={1, 10, 100, 1000, 10\:000, 100\:000}$.
For some reason to get the determinant of the same order of magnitude as in the vanilla onion method, I need to put $\eta=0$ and not $\eta=1$ (as claimed by LKJ). Not sure where the mistake is.
%// 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
Vine method
Vine method was originally suggested by Joe (J in LKJ) and improved by LKJ. I like it more, because it is conceptually easier and also easier to modify. The idea is to generate $d(d-1)/2$ partial correlations (they are independent and can have any values from $[-1, 1]$ without any constraints) and then convert them into raw correlations via a recursive formula. It is convenient to organize the computation in a certain order, and this graph is known as "vine". Importantly, if partial correlations are sampled from particular beta distributions (different for different cells in the matrix), then the resulting matrix will be distributed uniformly. Here again, LKJ introduce an additional parameter $\eta$ to sample from a distribution proportional to $[\mathrm{det}\:\mathbf C]^{\eta-1}$. The result is identical to the extended onion:
%// 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
Vine method with manual sampling of partial correlations
As one can see above, uniform distribution results in almost-diagonal correlation matrices. But one can easily modify the vine method to have stronger correlations (this is not described in the LKJ paper, but is straightforward): for this one should sample partial correlations from a distribution concentrated around $\pm 1$. Below I sample them from beta distribution (rescaled from $[0,1]$ to $[-1, 1]$) with $\alpha=\beta={50, 20, 10, 5, 2, 1}$. The smaller the parameters of the beta distribution, the more it is concentrated near the edges.
Note that in this case the distribution is not guaranteed to be permutation invariant, so I additionally randomly permute rows and columns after generation.
%// 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
Here is how the histograms of the off-diagonal elements look for the matrices above (variance of the distribution monotonically increases):
Update: using random factors
One really simple method of generating random correlation matrices with some strong correlations was used in the answer by @shabbychef, and I would like to illustrate it here as well. The idea is to randomly generate several ($k<d$) factor loadings $\mathbf W$ (random matrix of $k \times d$ size), form the covariance matrix $\mathbf W \mathbf W^\top$ (which of course will not be full rank) and add to it a random diagonal matrix $\mathbf D$ with positive elements to make $\mathbf B = \mathbf W \mathbf W^\top + \mathbf D$ full rank. The resulting covariance matrix can be normalized to become a correlation matrix, by letting $\mathbf C = \mathbf E^{-1/2}\mathbf B \mathbf E^{-1/2}$, where $\mathbf E$ is a diagonal matrix with the same diagonal as $\mathbf B$. This is very simple and does the trick. Here are some example correlation matrices for $k={100, 50, 20, 10, 5, 1}$:
And the 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
Here is the wrapping code used to generate the figures:
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