Obtenir N nombres aléatoires que la somme est M
je veux obtenir N nombres aléatoires que la somme d'eux est une valeur.
par exemple, supposons que je veux 5 nombres aléatoires que leur somme est 1
alors, une possibilité valide est:
0.2 0.2 0.2 0.2 0.2
autre possibilité:
0.8 0.1 0.03 0.03 0.04
et ainsi de suite. J'en ai besoin pour la création de la matrice des biens du flou C-means.
9 réponses
juste générer N nombres aléatoires, calculer leur somme, diviser chacun par la somme.
génèrent des nombres aléatoires N-1 entre 0 et 1, ajoutent les nombres 0 et 1 eux-mêmes à la liste, les trient, et prennent les différences des nombres adjacents.
je pense qu'il est intéressant de noter que le actuellement accepté de répondre ne donne pas une distribution uniforme:
"Juste générer des N nombres aléatoires, calculez leur somme, divisez chacun par la somme de "
pour voir ceci regardons le cas N=2 et M=1. C'est un cas trivial, puisque nous pouvons générer une liste [x,1-x], en choisissant x uniformément dans l'intervalle (0,1). La solution proposée génère paire [x/(x+y), y/(x+y)] où x et y sont uniformes (0,1). Pour analyser ceci nous choisissons un certain z tel que 0 < z < 0.5 et calculons la probabilité que le premier élément est plus petit que z. Cette probabilité devrait être de z si la distribution était uniforme. Cependant, nous obtenons
Prob(x/(x+y) < z) = Prob(x < z(x+y)) = Prob(x(1-z) < zy) = Prob(x < y(z/(1-z))) = z/(2-2z).
j'ai fait quelques calculs rapides et il semble que la seule solution jusqu'à présent qu'il s'agit d'obtenir une distribution uniforme a été proposé par Matti Virkkunen :
"Générer des N-1 nombres aléatoires entre 0 et 1, ajouter les numéros 0 et 1 à la liste, de les trier, et de prendre les différences de nombres adjacents."
En Java:
private static double[] randSum(int n, double m) {
Random rand = new Random();
double randNums[] = new double[n], sum = 0;
for (int i = 0; i < randNums.length; i++) {
randNums[i] = rand.nextDouble();
sum += randNums[i];
}
for (int i = 0; i < randNums.length; i++) {
randNums[i] /= sum * m;
}
return randNums;
}
ce problème est équivalent au problème de générer des nombres aléatoires avec une distribution de Dirichlet . Pour générer N nombres positifs qui se additionnent à un nombre positif M, où chaque combinaison possible est également probable:
-
Générer N exponentiellement distribué des nombres aléatoires. Une façon de générer un tel nombre peut être écrit comme -
number = -ln(1.0 - RNDU())
où
ln(x)
est le logarithme naturel dex
etRNDU()
est une méthode qui retourne un nombre aléatoire de 0 ou plus et moins de 1 (par exemple, JavaScriptMath.random()
). Notez que générer ces nombres avec une distribution uniforme n'est pas idéal parce qu'une distribution biaisée des combinaisons de nombres aléatoires en résultera. - divisez les nombres générés de cette façon par leur somme.
- multiplier chaque nombre par M.
le résultat est N nombres dans une distribution de Dirichlet dont la somme est approximativement égale à M (je dis "approximativement" en raison d'une erreur d'arrondissement).
ce problème est également équivalent au problème de générant des nombres aléatoires uniformément à partir d'un simplex n-dimensionnel .
juste générer N nombres aléatoires, calculer leur somme, diviser chacun par somme.
S'étendant sur la réponse acceptée de Guillaume , voici une fonction Java qui fait exactement cela.
public static double[] getRandDistArray(int n, double m)
{
double randArray[] = new double[n];
double sum = 0;
// Generate n random numbers
for (int i = 0; i < randArray.length; i++)
{
randArray[i] = Math.random();
sum += randArray[i];
}
// Normalize sum to m
for (int i = 0; i < randArray.length; i++)
{
randArray[i] /= sum;
randArray[i] *= m;
}
return randArray;
}
Dans un essai, getRandDistArray(5, 1.0)
a renvoyé le texte suivant:
[0.38106150346121903, 0.18099632814238079, 0.17275044310377025, 0.01732932296660358, 0.24786240232602647]
- générer des nombres aléatoires N-1.
- calcule la somme desdits nombres.
- ajouter la différence entre la somme calculée et la somme désirée à l'ensemble.
vous avez maintenant N nombres aléatoires, et leur somme est la somme désirée.
Malheureusement, un certain nombre de réponses ici sont incorrectes si vous souhaitez uniformément nombres aléatoires. La solution la plus facile (et la plus rapide dans de nombreuses langues) qui garantit des nombres aléatoires uniformes est juste
# This is Python, but most languages support the Dirichlet.
import numpy as np
np.random.dirichlet(np.ones(n))*m
où n
est le nombre de nombres aléatoires que vous voulez générer et m
est la somme du tableau résultant. Cette approche produit des valeurs positives et est particulièrement utile pour générer des probabilités valides qui totalisent 1 (soit m = 1).
Vous êtes un peu mince sur les contraintes. Beaucoup de procédures fonctionneront.
par exemple, les numéros sont-ils normalement distribués? Uniforme?
Je suppose que tous les nombres doivent être positifs et uniformément répartis autour de la moyenne, M/N.
essayez ceci.
- moyenne= M/N.
- génère des valeurs N-1 entre 0 et 2*moyenne. Cela peut être un nombre compris entre 0 et 1, u , et la valeur aléatoire est (2*u-1)*moyenne pour créer une valeur dans une plage appropriée.
- calcule la somme des valeurs N-1.
- la valeur restante est n-sum.
- si la valeur restante ne correspond pas aux contraintes (moyenne de 0 à 2*), répéter la procédure.