Получение N случайных чисел с суммой M

Я хочу получить 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 ответов

Решение

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

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

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

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

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

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

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

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

"Просто сгенерируйте 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 в список, отсортируйте их и возьмите различия соседних чисел".

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

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

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

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

    number = -ln(1.0 - RNDU())
    

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

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

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

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

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

Просто сгенерируйте 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. Генерация N-1 случайных чисел.
  2. Вычислить сумму указанных чисел.
  3. Добавьте разницу между вычисленной суммой и желаемой суммой в набор.

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

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

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

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

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