Выбирая 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 переменных:

enter image description here

Есть ли у вас идея хорошего алгоритма выбора чисел, которые приводят к более равномерному или простому распределению?

Ответ 1

Вы хотите разбить расстояние от 0 до 1.

Выберите n - 1 чисел от 0 до 1, отсортируйте их и определите расстояния между ними.

Это разделит пространство 0 на 1, что должно дать случайный большой результат, который вы не получаете.

Тем не менее, при больших значениях n вы также можете ожидать, что ваше максимальное значение также уменьшится, но не так быстро, как ваш метод.

Ответ 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))

Это делает более высокие числа более вероятными.