Выбирая n чисел с фиксированной суммой
В некотором коде я хочу выбрать n
случайные числа в [0,1)
, которые суммируются с 1
.
Я делаю это, выбирая числа независимо в [0,1)
и нормализуя их, деля их на общую сумму:
numbers = [random() for i in range(n)]
numbers = [n/sum(numbers) for n in numbers]
Моя "проблема" заключается в том, что распределение, которое я получаю, довольно искажено. Выбрав миллион номеров, ни один из них не перейдет 1/2
. Некоторое усилие я вычислил pdf, и это не приятно.
Вот странный вид pdf, который я получаю для 5 переменных:
Есть ли у вас идея хорошего алгоритма выбора чисел, которые приводят к более равномерному или простому распределению?
Ответы
Ответ 1
Вы хотите разбить расстояние от 0 до 1.
Выберите n - 1 чисел от 0 до 1, отсортируйте их и определите расстояния между ними.
Это разделит пространство 0 на 1, что должно дать случайный большой результат, который вы не получаете.
Тем не менее, при больших значениях n вы также можете ожидать, что ваше максимальное значение также уменьшится, но не так быстро, как ваш метод.
Ответ 2
Взгляните на Случайные векторы с фиксированной суммой. Ссылка на скачивание приводит к файлу с кодом MATLAB и документом, объясняющим алгоритм.
Ответ 3
Возможно, вас заинтересует дистрибутив Дирихле, который используется для генерации количеств, сумма которых равна 1, если вы ищете вероятности. Там также раздел о том, как их генерировать с использованием гамма-распределений здесь.
Ответ 4
Другой способ получить n
случайные числа, которые суммируются до 1:
import random
def create_norm_arr(n, remaining=1.0):
random_numbers = []
for _ in range(n - 1):
r = random.random() # get a random number in [0, 1)
r = r * remaining
remaining -= r
random_numbers.append(r)
random_numbers.append(remaining)
return random_numbers
random_numbers = create_norm_arr(5)
print(random_numbers)
print(sum(random_numbers))
Это делает более высокие числа более вероятными.