Получение N случайных чисел с суммой M - PullRequest
38 голосов
/ 14 апреля 2010

Я хочу получить N случайных чисел, сумма которых равна значению.

Например, предположим, что я хочу 5 случайных чисел, сумма которых равна 1.

Тогда допустимая возможность:

0.2 0.2 0.2 0.2 0.2

Другая возможность:

0.8 0.1 0.03 0.03 0.04

И так далее. Мне это нужно для создания матрицы вещей для нечетких C-средних.

Ответы [ 9 ]

54 голосов
/ 14 апреля 2010

Краткий ответ:

Просто сгенерируйте N случайных чисел, вычислите их сумму, разделите каждое на сумму и умножьте на М.

Более длинный ответ:

Приведенное выше решение не дает равномерное распределение, которое может быть проблемой в зависимости от того, для чего используются эти случайные числа. Другой метод, предложенный Матти Вирккуненом:

Генерация N-1 случайных чисел от 0 до 1, добавление чисел от 0 до 1 сами к списку, сортировать их, и взять различия соседние числа.

Я не уверен, дает ли это равномерное распределение

41 голосов
/ 14 апреля 2010

Создайте N-1 случайных чисел от 0 до 1, добавьте сами номера 0 и 1 в список, отсортируйте их и возьмите различия соседних чисел.

26 голосов
/ 15 апреля 2010

Я думаю, что стоит отметить, что текущий принятый ответ не дает равномерного распределения:

"Просто сгенерируйте N случайных чисел, рассчитать их сумму, разделить каждый на сумма "

Чтобы увидеть это, давайте посмотрим на случай N = 2 и M = 1. Это тривиальный случай, поскольку мы можем сгенерировать список [x, 1-x], выбрав x равномерно в диапазоне (0,1). Предложенное решение генерирует пару [x / (x + y), y / (x + y)], где x и y равномерны в (0,1). Чтобы проанализировать это, мы выбираем некоторый z такой, что 0

Prob (x / (x + y)

Я провел несколько быстрых вычислений, и оказалось, что единственное решение, которое до сих пор приводило к равномерному распределению, было , предложенное Матти Вирккуненом :

"Сгенерируйте N-1 случайных чисел от 0 до 1, добавьте сами номера 0 и 1 в список, отсортируйте их и возьмите различия соседних чисел."

4 голосов
/ 15 апреля 2010

В 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;
}
2 голосов
/ 25 июля 2017

Эта проблема эквивалентна задаче генерации случайных чисел с распределением Дирихле . Чтобы сгенерировать N положительных чисел, которые суммируются с положительным числом M, где каждая возможная комбинация одинаково вероятна:

  • Генерация N экспоненциально распределенных случайных чисел. Один из способов создания такого числа можно записать как & mdash;

    number = -ln(1.0 - RNDU())
    

    , где ln(x) - натуральный логарифм x, а RNDU() - метод, который возвращает случайное число 0 или больше и меньше 1 (например, JavaScript Math.random()). Обратите внимание, что генерация этих чисел с равномерным распределением не идеальна, так как это приведет к смещенному распределению комбинаций случайных чисел.

  • Разделите сгенерированные таким образом числа на их сумму.
  • Умножьте каждое число на М.

Результатом является N чисел в распределении Дирихле, сумма которых приблизительно равна M (я говорю "приблизительно" из-за ошибки округления).

Эта проблема также эквивалентна проблеме генерации случайных чисел равномерно из N-мерного симплекса .

2 голосов
/ 02 апреля 2017

Просто сгенерируйте N случайных чисел, вычислите их сумму, разделите каждое на сумма.

Расширение принятого ответа Гийома , вот функция Java, которая делает именно это.

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;
}

В тестовом прогоне getRandDistArray(5, 1.0) вернул следующее:

[0.38106150346121903, 0.18099632814238079, 0.17275044310377025, 0.01732932296660358, 0.24786240232602647]
1 голос
/ 26 июня 2018

К сожалению, некоторые ответы здесь неверны, если вы хотите получить равномерно случайные числа. Самое простое (и самое быстрое во многих языках) решение, которое гарантирует равномерно случайные числа, это всего лишь

# This is Python, but most languages support the Dirichlet.
import numpy as np
np.random.dirichlet(np.ones(n))*m

где n - количество случайных чисел, которые вы хотите сгенерировать, а m - сумма результирующего массива. Этот подход дает положительные значения и особенно полезен для генерации действительных вероятностей, которые составляют 1 (пусть m = 1).

1 голос
/ 14 апреля 2010
  1. Генерирует N-1 случайных чисел.
  2. Вычислить сумму указанных чисел.
  3. Добавьте разницу между вычисленной суммой и желаемой суммой к набору.

Теперь у вас есть N случайных чисел, и их сумма является желаемой суммой.

0 голосов
/ 14 апреля 2010

Ты немного стройен в ограничениях. Много и много процедур будет работать.

Например, нормально ли распределены числа? Равномерное
Я предполагаю, что все числа должны быть положительными и равномерно распределенными по среднему, M / N.

Попробуйте это.

  1. среднее = М / Н.
  2. Генерирует значения N-1 от 0 до 2 * среднее. Это может быть стандартное число от 0 до 1, u , и случайное значение (2 * u-1) * означает создание значения в соответствующем диапазоне.
  3. Вычислить сумму значений N-1.
  4. Оставшееся значение равно N-сумме.
  5. Если оставшееся значение не соответствует ограничениям (среднее значение от 0 до 2 *), повторите процедуру.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...