Je vois si souvent cette erreur, la suggestion que pour générer des nombres aléatoires avec une somme donnée, il suffit d'utiliser un ensemble aléatoire uniforme, et de les mettre à l'échelle. Mais le résultat est-il vraiment uniformément aléatoire si l'on procède de cette façon ?
Essayez ce test simple en deux dimensions. Générez un énorme échantillon aléatoire, puis mettez-le à l'échelle pour que sa somme soit égale à 1. Je vais utiliser bsxfun pour faire la mise à l'échelle.
xy = rand(10000000,2);
xy = bsxfun(@times,xy,1./sum(xy,2));
hist(xy(:,1),100)
S'ils étaient vraiment uniformément aléatoires, alors la coordonnée x serait uniforme, tout comme la coordonnée y. Toutes les valeurs auraient la même probabilité de se produire. En effet, pour que la somme de deux points soit égale à 1, ils doivent se trouver le long de la ligne qui relie les deux points (0,1), (1,0) dans le plan (x,y). Pour que les points soient uniformes, tout point le long de cette ligne doit avoir la même probabilité.
L'uniformité échoue clairement lorsque j'utilise la solution de mise à l'échelle. Tous les points de cette ligne n'ont PAS la même probabilité. Nous pouvons voir la même chose se produire en 3 dimensions. Vous voyez que dans la figure en 3 dimensions, les points au centre de la région triangulaire sont plus denses. C'est le reflet de la non-uniformité.
xyz = rand(10000,3);
xyz = bsxfun(@times,xyz,1./sum(xyz,2));
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on
Là encore, la solution de la mise à l'échelle simple échoue. Elle ne produit tout simplement PAS de résultats vraiment uniformes sur le domaine d'intérêt.
Peut-on faire mieux ? Eh bien, oui. Une solution simple en 2-d consiste à générer un seul nombre aléatoire qui désigne la distance le long de la ligne reliant les points (0,1) et 1,0).
t = rand(10000000,1);
xy = t*[0 1] + (1-t)*[1 0];
hist(xy(:,1),100)
On peut montrer que n'importe quel point de la ligne définie par l'équation x+y = 1, dans le carré unitaire, a maintenant la même probabilité d'avoir été choisi. Ceci est reflété par le bel histogramme plat.
L'astuce suggérée par David Schwartz fonctionne-t-elle en n-dimensions ? Il est clair qu'il fonctionne en 2 dimensions, et la figure ci-dessous suggère qu'il fonctionne en 3 dimensions. Sans avoir réfléchi profondément à la question, je pense que cela fonctionnera pour le cas de base en question, en n-dimensions.
n = 10000;
uv = [zeros(n,1),sort(rand(n,2),2),ones(n,1)];
xyz = diff(uv,[],2);
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
box on
grid on
view(70,35)
On peut également télécharger la fonction randfixedsum de l'échange de fichiers, la contribution de Roger Stafford. Il s'agit d'une solution plus générale pour générer des ensembles aléatoires véritablement uniformes dans l'hypercube unitaire, avec une somme fixe donnée. Ainsi, pour générer des ensembles aléatoires de points situés dans le cube 3 unitaire, soumis à la contrainte que leur somme soit égale à 1,25...
xyz = randfixedsum(3,10000,1.25,0,1)';
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on