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.

37
demandé sur Peter O. 2010-04-14 22:37:38

9 réponses

juste générer N nombres aléatoires, calculer leur somme, diviser chacun par la somme.

51
répondu Guillaume 2015-10-14 13:00:01

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.

40
répondu Matti Virkkunen 2010-04-14 18:41:16

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."

26
répondu Accipitridae 2017-05-23 12:10:34

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;
}
4
répondu Vortico 2018-02-16 21:56:25

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

    ln(x) est le logarithme naturel de x et RNDU() est une méthode qui retourne un nombre aléatoire de 0 ou plus et moins de 1 (par exemple, JavaScript Math.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 .

2
répondu Peter O. 2017-10-12 10:09:39

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]
2
répondu Steven Vascellaro 2018-02-16 18:13:42
  1. générer des nombres aléatoires N-1.
  2. calcule la somme desdits nombres.
  3. 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.

1
répondu Yuval 2010-04-14 19:13:50

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

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

1
répondu cgnorthcutt 2018-06-26 18:37:49

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.

  1. moyenne= M/N.
  2. 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.
  3. calcule la somme des valeurs N-1.
  4. la valeur restante est n-sum.
  5. si la valeur restante ne correspond pas aux contraintes (moyenne de 0 à 2*), répéter la procédure.
0
répondu S.Lott 2010-04-14 18:51:38