Получение 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 (например, JavaScriptMath.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]
- Генерация N-1 случайных чисел.
- Вычислить сумму указанных чисел.
- Добавьте разницу между вычисленной суммой и желаемой суммой в набор.
Теперь у вас есть N случайных чисел, и их сумма является желаемой суммой.
Вы немного стройны в ограничениях. Много и много процедур будет работать.
Например, нормально ли распределены числа? Равномерное?
Я предполагаю, что все числа должны быть положительными и равномерно распределенными по среднему, M/N.
Попробуй это.
- среднее = M/N.
- Генерируйте значения N-1 от 0 до 2* среднее. Это может быть стандартное число от 0 до 1, u, и случайное значение (2*u-1)* означает создание значения в соответствующем диапазоне.
- Вычислить сумму значений N-1.
- Оставшееся значение равно N-сумме.
- Если оставшееся значение не соответствует ограничениям (среднее значение от 0 до 2*), повторите процедуру.