web-dev-qa-db-fra.com

Des nombres aléatoires qui s'ajoutent à 100: Matlab

[Je divise un nombre de population en différentes matrices et je veux tester mon code en utilisant des nombres aléatoires pour l'instant.]

Question rapide les gars et merci pour votre aide à l'avance -

Si j'utilise;

 100*Rand(9,1)

Quelle est la meilleure façon de faire ajouter ces 9 nombres à 100?

Je voudrais 9 nombres aléatoires entre 0 et 100 qui totalisent 100.

Y a-t-il une commande intégrée qui fait cela parce que je n'arrive pas à la trouver.

40
Tetra

Je vois si souvent l'erreur, la suggestion que pour générer des nombres aléatoires avec une somme donnée, on utilise simplement un ensemble aléatoire uniforme, et juste les mettre à l'échelle. Mais le résultat est-il vraiment uniformément aléatoire si vous le faites de cette façon?

Essayez ce test simple en deux dimensions. Générez un énorme échantillon aléatoire, puis redimensionnez-les pour additionner à 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. Toute valeur serait également susceptible de se produire. En effet, pour que deux points totalisent 1, ils doivent se situer 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 être également probable.

xy histogram

Il est clair que l'uniformité échoue lorsque j'utilise la solution de mise à l'échelle. Tout point sur cette ligne n'est PAS aussi probable. Nous pouvons voir la même chose se produire en 3 dimensions. Voyez que dans la figure 3D ici, les points au centre de la région triangulaire sont plus densément emballés. Ceci 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

xyzplot

Encore une fois, la solution de mise à l'échelle simple échoue. Il ne produit tout simplement PAS de résultats vraiment uniformes dans le domaine d'intérêt.

Pouvons-nous faire mieux? Hé bien oui. Une solution simple en 2D est de 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)

Uniform x+y = 1

On peut montrer que N'IMPORTE QUEL point le long de la ligne définie par l'équation x + y = 1, dans le carré de l'unité, est désormais également susceptible d'avoir été choisi. Cela se reflète dans l'histogramme plat de Nice.

L'astuce de tri proposée par David Schwartz fonctionne-t-elle en n dimensions? De toute évidence, il le fait en 2D, et la figure ci-dessous suggère qu'il le fait en 3D. Sans une réflexion approfondie sur la question, je pense que cela fonctionnera pour ce 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)

Sort trick

On peut également télécharger la fonction randfixedsum à partir de l'échange de fichiers, contribution de Roger Stafford. Il s'agit d'une solution plus générale pour générer des ensembles aléatoires vraiment uniformes dans l'hyper-cube unitaire, avec une somme fixe donnée. Ainsi, pour générer des ensembles aléatoires de points qui se trouvent dans l'unité 3-cube, soumis à la contrainte, ils totalisent 1,25 ...

xyz = randfixedsum(3,10000,1.25,0,1)';
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'.')
view(70,35)
box on
grid on

randfixedsum

80
user85109

Une façon simple consiste à choisir 8 nombres aléatoires entre 0 et 100. Ajoutez 0 et 100 à la liste pour donner 10 nombres. Triez-les. Puis sortez la différence entre chaque paire de nombres successifs. Par exemple, voici 8 nombres aléatoires entre 0 et 100:

96, 38, 95, 5, 13, 57, 13, 20

Ajoutez donc 0 et 100 et triez.

0, 5, 13, 13, 20, 38, 57, 95, 96, 100

Soustrayez maintenant:

5-0 = 5
13-5 = 8
13-13 = 0
20-13 = 7
38-20 = 18
57-38 = 19
95-57 = 38
96-95 = 1
100-96 = 4

Et là vous l'avez, neuf nombres qui totalisent 100: 0, 1, 4, 5, 7, 8, 18, 19, 38. Que j'ai obtenu un zéro et un était juste une étrange chance.

63
David Schwartz

Il n'est pas trop tard pour donner la bonne réponse

Parlons de l'échantillonnage de X1 ... XN dans la plage [0 ... 1] de sorte que Sum (X1, ..., XN) soit égal à 1. Ensuite, vous pouvez le redimensionner à 100

Cela s'appelle distribution Dirichlet , et ci-dessous se trouve le code à en échantillonner. Le cas le plus simple est lorsque tous les paramètres sont égaux à 1, alors toutes les distributions marginales pour X1, ..., XN seraient U (0,1). En général, avec des paramètres différents de 1, les distributions marginales peuvent avoir des pics.

----------------- tiré de ici ---------------------

Le Dirichlet est un vecteur de variables aléatoires gamma à échelle unitaire, normalisées par leur somme. Donc, sans vérification d'erreur, cela vous permettra de:

a = [1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0]; // 9 numbers to sample
n = 10000;
r = drchrnd(a,n)

function r = drchrnd(a,n)
  p = length(a);
  r = gamrnd(repmat(a,n,1),1,n,p);
  r = r ./ repmat(sum(r,2),1,p);
6
Severin Pappadeux

Prenez une liste de N - 1 nombres, créez une liste de N + 1 nombres en insérant 0 et 100, triez la liste et différez-les jusqu'à un total de N nombres.

0
user2392848