Comment générer efficacement des matrices de corrélation positives-semi-définies aléatoires?

38

J'aimerais pouvoir générer efficacement des matrices de corrélation positive semi-définie (PSD). Ma méthode ralentit considérablement lorsque j'augmente la taille des matrices à générer.

  1. Pourriez-vous suggérer des solutions efficaces? Si vous connaissez des exemples dans Matlab, je vous en serais très reconnaissant.
  2. Lors de la génération d'une matrice de corrélation PSD, comment choisir les paramètres pour décrire les matrices à générer? Une corrélation moyenne, écart type de corrélations, valeurs propres?
Eduardas
la source

Réponses:

16

Vous pouvez le faire en arrière: chaque matrice (l’ensemble de toutes les matrices PSD p × p symétriques ) peut être décomposée en tant queCR++pp×p

O est une matrice orthonorméeC=OTDOO

Pour obtenir , d' abord générer une base aléatoire ( v 1 , . . . , V p ) (où v i sont des vecteurs aléatoires, typiquement dans ( - 1 , 1 ) ). De là, en utilisant le procédé d'orthogonalisation de Gram-Schmidt pour obtenir ( u 1 , . . . . , U p ) = OO(v1,...,vp)vi(1,1)(u1,....,up)=O

possède un certain nombre de packages qui peuvent effectuer l'orthogonalisation GS d'une base aléatoire de manière efficace, même pour les grandes dimensions, par exemple le package "far". Bien que vous trouviez l'algorithme GS sur wiki, il vaut probablement mieux ne pas réinventer la roue et opter pour une implémentation de matlab (il en existe sûrement, je ne peux en recommander aucune).R

Enfin, est une matrice diagonale dont tous les éléments sont positifs (encore une fois, c’est facile à générer: générez p nombres aléatoires, positionnez-les, triez-les et placez-les à la diagonale d’une matrice identité p sur p ).Dppp

utilisateur603
la source
3
(1) Notez que le résultant ne sera pas une matrice de corrélation (comme demandé par l'OP), car il n'en aura pas sur la diagonale. Bien sûr , il peut être étalonnée pour avoir ceux sur la diagonale, en mettant à E - 1 / 2 C E - 1 / 2 , où E est une matrice diagonale avec la même diagonale que C . (2) Si je ne me trompe pas, cela se traduira par des matrices de corrélation où tous les éléments non diagonaux sont concentrés autour de 0 ; il n'y a donc aucune flexibilité recherchée par l'OP (l'OP souhaitait pouvoir définir "une corrélation moyenne , écart type des corrélations, valeurs propres "CE-1/2CE-1/2EC0)
amibe dit de réintégrer Monica
@ amoeba: Je vais aborder (2) car, comme vous le signalez, la solution à (1) est triviale. La caractérisation en un nombre de la «forme» (la relation entre les éléments diagonaux entrant et sortant) d'une matrice PSD (et donc d'une covariance ainsi que d'une matrice de corrélation) est son numéro de condition. Et, la méthode décrite ci-dessus permet un contrôle total sur elle. La "concentration des éléments non diagonaux autour de 0" n'est pas une caractéristique de la méthode utilisée pour générer des matrices de DSP, mais plutôt une conséquence des contraintes nécessaires pour garantir que la matrice est une DSP et du fait que est grand. p
user603
Voulez-vous dire que toutes les grandes matrices de PSD ont des éléments non diagonaux proches de zéro? Je ne suis pas d'accord, ce n'est pas le cas. Vérifiez ma réponse ici pour quelques exemples: Comment générer une matrice de corrélation aléatoire comportant des entrées hors diagonale approximativement normalement distribuées avec un écart-type donné? Mais on peut voir directement que ce n’est pas le cas, car une matrice carrée ayant toutes des unités sur la diagonale et une valeur fixe partout hors diagonale est PSD et ρ peut être arbitrairement grand (mais naturellement inférieur à 1 ). ρρ1
amibe dit de réintégrer Monica
@ amoeba: alors j'ai eu tort de supposer que, par nécessité, la diagonale des grandes matrices de corrélation quand elles sont autorisées à être à la fois positives et négatives sont proches de 0. Merci pour cet exemple éclairant.
user603
1
J'ai lu un très bon article sur la génération de matrices de corrélation aléatoire et fourni ma propre réponse ici (ainsi qu'une autre réponse dans ce fil lié). Je pense que vous pourriez trouver cela intéressant.
Amibe dit de réintégrer Monica
27

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 ) / 2×(-1)/2R(-1)/2R(-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 .=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

Méthode de l'oignon

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[etC]η-1ηη=1 .η=1,dix,100,1000,dix000,100000

Méthode de l'oignon étendu

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 ](-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:[etC]η-1

Méthode de la vigne

%// 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,dix,5,2,1. Plus les paramètres de la distribution bêta sont petits, plus elle est concentrée près des bords.

Méthode de la vigne avec échantillonnage manuel

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):

Éléments hors diagonale


Mise à jour: utilisation de facteurs aléatoires

k<Wk×WWB=WW+C=E-1/2BE-1/2EBk=100,50,20,dix,5,1

matrices de corrélation aléatoire à partir de facteurs aléatoires

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
l'amibe dit de réintégrer Monica
la source
2
C'est un résumé fantastique, je suis content d'avoir dit quelque chose!
shadowtalker
Lorsque j'ai traduit le code matlab de la matrice de corrélation basée sur la vigne en R et que je l'ai testé, la densité des corrélations de la colonne 1 était toujours différente de celle des colonnes suivantes. Peut-être que j'ai mal traduit quelque chose, mais peut-être que cette note aide quelqu'un.
Charlie
3
Pour les utilisateurs de R, la fonction rcorrmatrix du paquet clusterGeneration (écrite par W Qui et H. Joe) implémente la méthode vine.
RNM
15

Une caractérisation encore plus simple est celle de la matrice réelle UNE, UNETUNEest positif semi-défini. Pour voir pourquoi c'est le cas, il suffit de prouver queyT(UNETUNE)y0 pour tous les vecteurs y(de la bonne taille, bien sûr). C'est trivial:yT(UNETUNE)y=(UNEy)TUNEy=||UNEy||ce qui est non négatif. Donc, dans Matlab, essayez simplement

A = randn(m,n);   %here n is the desired size of the final matrix, and m > n
X = A' * A;

Selon l’application, il se peut que cela ne vous donne pas la distribution des valeurs propres souhaitée; La réponse de Kwak est bien meilleure à cet égard. Les valeurs propres de Xcet extrait de code doivent correspondre à la distribution de Marchenko-Pastur.

Pour simuler les matrices de corrélation des actions, supposons une approche légèrement différente:

k = 7;      % # of latent dimensions;
n = 100;    % # of stocks;
A = 0.01 * randn(k,n);  % 'hedgeable risk'
D = diag(0.001 * randn(n,1));   % 'idiosyncratic risk'
X = A'*A + D;
ascii_hist(eig(X));    % this is my own function, you do a hist(eig(X));
-Inf <= x <  -0.001 : **************** (17)
-0.001 <= x <   0.001 : ************************************************** (53)
 0.001 <= x <   0.002 : ******************** (21)
 0.002 <= x <   0.004 : ** (2)
 0.004 <= x <   0.005 :  (0)
 0.005 <= x <   0.007 : * (1)
 0.007 <= x <   0.008 : * (1)
 0.008 <= x <   0.009 : *** (3)
 0.009 <= x <   0.011 : * (1)
 0.011 <= x <     Inf : * (1)
shabbychef
la source
1
seriez-vous prêt à partager votre fonction ascii_hist par hasard?
Ville le
@btown la marge est trop petite pour la contenir!
Shabbychef
1
Il y a une faute de frappe dans yT(UNETUNE)y=(UNEy)TUNEy=||UNEy||- Il manque sa dernière case!
Silverfish
8

En variante à la réponse du kwak: générer une matrice diagonale avec des valeurs propres non négatives aléatoires à partir d'une distribution de votre choix, puis effectuez une transformation de similarité UNE=QQT avec Qune matrice orthogonale pseudo-aléatoire distribuée par Haar .

JM n'est pas un statisticien
la source
M.: Référence de Nice: Cela semble être la solution la plus efficace (asymptotiquement).
whuber
3
@ Whuber: Hé, je l'ai pris à Golub et à Van Loan (bien sûr); Je l’utilise tout le temps pour aider à générer des matrices de test pour les routines de test de contraintes propres / valeurs singulières. Comme on peut le voir dans le document, cela revient essentiellement à décomposer par QR une matrice aléatoire comme celle suggérée par le kwak, à la différence que cela se fait de manière plus efficace. Il existe une implémentation MATLAB de cela dans la boîte à outils Text Matrix Toolbox, BTW.
JM n'est pas un statisticien le
M.:> Merci pour l'implémentation de matlab. Connaissez-vous par hasard un générateur de matrice pseudo-aléatoire de Haar dans R?
user603
@kwak: Aucune idée, mais s'il n'y a pas encore d'implémentation, il ne devrait pas être trop difficile de traduire le code MATLAB en R (je peux essayer d'en créer un s'il n'y en a pas); le seul pré-requis est un générateur décent pour les variables normales pseudo-aléatoires, que R possède, j'en suis sûr.
JM n'est pas statisticien le
M.:> oui je vais probablement le traduire moi-même. Merci pour les liens, Best.
user603
4

Vous n'avez pas spécifié de distribution pour les matrices. Deux distributions communes sont les distributions de Wishart et inverses de Wishart. La décomposition de Bartlett donne une factorisation de Cholesky d'une matrice de Wishart aléatoire (qui peut également être résolue efficacement pour obtenir une matrice de Wishart inverse aléatoire).

En fait, l'espace de Cholesky est un moyen pratique de générer d'autres types de matrices de PSD aléatoires, car il vous suffit de vous assurer que la diagonale est non négative.

Simon Byrne
la source
> Non aléatoire: deux matrices générées à partir du même Whishard ne seront pas indépendantes l'une de l'autre. Si vous envisagez de changer le Whishart à chaque génération, comment envisagez-vous de générer ces Whishart en premier lieu?
user603
@kwak: Je ne comprends pas votre question: la décomposition de Bartlett donnera des tirages indépendants de la même distribution de Wishart.
Simon Byrne le
> Permettez-moi de reformuler ceci, d'où vous vient la matrice d'échelle de votre distribution de whishart?
user603
1
@kwak: c'est un paramètre de la distribution, et est donc corrigé. Vous la sélectionnez au début, en fonction des caractéristiques souhaitées de votre distribution (telles que la moyenne).
Simon Byrne le
3

La méthode la plus simple est celle ci-dessus, qui consiste à simuler un ensemble de données aléatoires et à calculer le gramian . Un mot de prudence: la matrice résultante ne sera pas uniformément aléatoire, en ce sens que sa décomposition, disonsUTSULes rotations ne seront pas réparties conformément à la mesure de Haar. Si vous souhaitez disposer de matrices PSD "uniformément réparties", vous pouvez utiliser l'une des approches décrites ici .

gappy
la source
Si les entrées sont générées à partir d'une distribution normale plutôt que d'uniforme, la décomposition que vous mentionnez doit être invariante par SO (n) (et donc équidistribuée par rapport à la mesure de Haar).
whuber
Intéressant. Pouvez-vous fournir une référence pour cela?
Gappy
1
> Le problème avec cette méthode est que vous ne pouvez pas contrôler le rapport de la valeur propre la plus petite à la plus grande (et je pense que si la taille de votre jeu de données généré aléatoirement va à l'infini, ce rapport convergera vers 1).
user603
1

Si vous souhaitez mieux contrôler votre matrice PSD symétrique générée, par exemple générer un jeu de données de validation synthétique, vous disposez d'un certain nombre de paramètres. Une matrice PSD symétrique correspond à une hyper-ellipse dans l'espace à N dimensions, avec tous les degrés de liberté correspondants:

  1. Rotations
  2. Longueurs des axes.

Ainsi, pour une matrice à 2 dimensions (c.-à-d. Ellipse 2d), vous aurez 1 rotation + 2 axes = 3 paramètres.

Si les rotations rappellent les matrices orthogonales, c’est un train correct, car la construction est à nouveau Σ=OOT, avec Σ étant la matrice Sym.PSD produite, O la matrice de rotation (qui est orthogonale), et la matrice diagonale, dont les éléments diagonaux contrôleront la longueur des axes de l'ellipse.

Le code Matlab ci-après représente 16 ensembles de données distribués gaussiens bidimensionnels basés sur Σ, avec un angle croissant. Le code pour la génération aléatoire de paramètres est dans les commentaires.

figure;
mu = [0,0];
for i=1:16
    subplot(4,4,i)
    theta = (i/16)*2*pi;   % theta = rand*2*pi;
    U=[cos(theta), -sin(theta); sin(theta) cos(theta)];
    % The diagonal's elements control the lengths of the axes
    D = [10, 0; 0, 1]; % D = diag(rand(2,1));    
    sigma = U*D*U';
    data = mvnrnd(mu,sigma,1000);
    plot(data(:,1),data(:,2),'+'); axis([-6 6 -6 6]); hold on;
end

Pour plus de dimensions, la matrice Diagonal est simple (comme ci-dessus), et le U découler de la multiplication des matrices de rotation.

PeriRamm
la source
0

Une méthode peu coûteuse et amusante que j’ai utilisée pour tester consiste à générer m N (0,1) n-vecteurs V [k], puis à utiliser P = d * I + Somme {V [k] * V [k] '} en tant que matrice nxn psd. Avec m <n, cela sera singulier pour d = 0, et pour petit d aura un nombre de condition élevé.


la source
2
> Le problème avec cette méthode est que vous ne pouvez pas contrôler le rapport de la valeur propre la plus petite à la plus grande (et je pense que si la taille de votre jeu de données généré aléatoirement va à l'infini, ce rapport convergera vers 1).
user603
De plus, la méthode n’est pas très efficace (du point de vue du calcul)
user603 le
1
Votre "matrice aléatoire" est une structure spécialement structurée appelée "matrice diagonale plus rang 1" (matrice DR1), donc pas vraiment une bonne matrice aléatoire représentative.
JM n'est pas un statisticien le