Создать пуассоновоподобное распределение с N случайными числами, сумма которых является константой (C)

1

Я хочу создать случайное распределение чисел Пуассона, где сумма сгенерированных чисел равна 1000, а нижняя верхняя граница распределения равна (3-30).

Я могу использовать numpy для генерации случайного числа:

 
In [2]: np.random.poisson(5, 150)
array([ 4,  4,  6,  4,  8,  6,  4,  2,  6,  8,  8,  8,  1,  4,  3,  4,  1,
        3,  7,  6,  7,  4,  5,  5,  7,  6,  5,  3,  3,  5,  4,  6,  2,  0,
        3,  5,  6,  2,  5,  2,  4,  7,  4,  7,  8,  5,  6,  1,  4,  4,  7,
        4,  7,  2,  7,  4,  3,  8, 10,  2,  5,  7,  6,  3,  5,  7,  8,  5,
        4,  7,  8,  8,  2,  2, 10,  6,  3,  5,  2,  5,  5,  6,  4,  6,  4,
        0,  4,  3,  5,  8,  6,  7,  4,  4,  4,  3,  3,  4,  4,  6,  7,  6,
        3,  9,  7,  7,  4,  5,  2,  4,  3,  6,  5,  6,  3,  6,  8,  9,  6,
        3,  4,  4,  7,  3,  9, 12,  4,  5,  5,  7,  6,  5,  2, 10,  1,  3,
        4,  4,  6,  5,  4,  4,  7,  5,  6,  5,  7,  2,  5,  5])


Но я хочу добавить к нему что-то еще:

- The random number should be minimal of 3 and max of 30 
- The sum of the generated random number should be 1000.

Я знаю, я могу не создавать точное распределение Пуассона, если я манипулирую. Но я хочу что-то вроде Пуассона, но с предлагаемыми средствами управления.

  • 0
    Количество значений всегда фиксировано?
  • 0
    Ваш вопрос не имеет смысла. Если у него минимум 3, это не Пуассон. Если случайные переменные добавляют к константе, они не являются независимыми Пуассона.
Показать ещё 12 комментариев
Теги:
pandas
numpy
numbers
random

3 ответа

2

Здесь есть еще одна альтернатива, основанная на предварительном распределении минимума на бункер, вычислении количества наблюдений и наборе по курсу Пуассона для каждого оставшегося бункера, определяемого количеством наблюдений и количеством оставшихся ящиков, но подлежащих принятию/отклонению на основе верхняя граница для бункера.

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

Вот:

import numpy as np

def make_poissonish(n, num_bins):
    if n > 30 * num_bins:
        print("requested n exceeds 30 / bin")
        exit(-1)
    if n < 3 * num_bins:
        print("requested n cannot fill 3 / bin")
        exit(-1)

    # Disperse minimum quantity per bin in all bins, then determine remainder
    lst = [3 for _ in range(num_bins)]
    number_remaining = n - num_bins * 3

    # Allocate counts to all bins using a truncated Poisson
    for i in range(num_bins):
        # dial the rate up or down depending on whether we're falling
        # behind or getting ahead in allocating observations to bins
        rate = number_remaining / float(num_bins - i)  # avg per remaining bin

        # keep generating until we meet the constraint requirement (acceptance/rejection)
        while True:
            x = np.random.poisson(rate)
            if x <= 27 and x <= number_remaining: break
        # Found an acceptable count, put it in this bin and move on
        lst[i] += x
        number_remaining -= x

    # If there are still observations remaining, disperse them
    # randomly across bins that have remaining capacity
    while number_remaining > 0:
        i = np.random.randint(0, num_bins)
        if lst[i] >= 30:    # not this one, it already full!
            continue
        lst[i] += 1
        number_remaining -= 1
    return lst

Пример вывода:

result = make_poissonish(150, 10)
print(result)                    # => [16, 19, 11, 16, 21, 18, 12, 17, 8, 12]
print(sum(result))               # => 150

result = make_poissonish(50, 10)
print(result)                    # => [3, 5, 5, 4, 3, 3, 15, 3, 6, 3]
print(sum(result))               # => 50
  • 0
    это действительно было полезно. Я сделал несколько модификаций, чтобы он соответствовал моим потребностям. Будет ли возможно связаться с вами (по электронной почте) для обсуждения статистики и моделирования.
2

Позвольте мне написать что-то, что могло бы работать или нет, мы увидим

Свойством распределения Пуассона является то, что один параметр - λ - одновременно является мерой среднего и дисперсии. Давайте попробуем другое распределение, которое действительно составляет 1000 и достаточно близко к Пуассону.

Я бы попробовал Multinomial Distribution. Давайте рассмотрим, что мы отбираем 200 чисел из многочлена. Мы будем сдвигать каждое выборочное число на 3, так что выполняется минимальное граничное условие. Это означает, что для выборочной многочленной суммы (параметр n) будет равно 1000 - 3 * 200 = 400. Вероятности p i будут установлены в 1/200.

Таким образом, для мультиномиального среднего E [x i ] = np i= 400/200 = 2. Отклонение от многочлена было бы = np i (1 - p i), а поскольку p i очень мало, термин (1 - p i) был бы почти близок к 1, тем самым делая выборку целых чисел, похожих на Пуассона со средним значением, равным дисперсии. Проблема в том, что после сдвига среднее значение равно 5, но дисперсия остается равной ~ 2.

Во всяком случае, какой-то код.

import numpy as np

N = 200
shift = 3
n = 1000 - N*shift
p = [1.0 / float(N)] * N

q = np.random.multinomial(n, p, size=1)
print(np.sum(q))
print(np.mean(q))
print(np.var(q))

result = q + shift
print(np.sum(result))
print(np.mean(result))
print(np.var(result))
  • 0
    p = [1.0 / float(N)] * N ? Я думаю, что вы имели в виду *n . Это похоже на хороший способ решения этой проблемы. Я собираюсь использовать simutale с помощью этого и внести необходимые улучшения.
  • 0
    @ everestial007 Нет, я имел в виду N , количество элементов для выборки. Итак, массив p_i содержит вероятности и нормирован. Пожалуйста, поделитесь результатами вашей симуляции, мне очень любопытно, работает ли она, а если нет, то почему
0

вы можете легко сделать это, используя цикл while и random module, и он выполнит эту задачу:

from random import randint
nums_sum = 0
nums_lst = list()
while nums_sum < 1000:
    n = randint(3, 31)
    nums_sum += n
    nums_lst.append(str(n))
    print(nums_sum)
    if 1000-nums_sum > 30: # means if the sum is more than 30 then complete ..
        continue
    else:
        nums_sum += 1000-nums_sum
print(nums_sum)
print(nums_lst)

так просто.

  • 0
    Привет, Хассан, это хороший способ преодолеть эту проблему, но я обеспокоен тем, что распространение должно быть возможным. Таким образом, средняя вероятность получения среднего значения выше, чем число в конце распределения. С рандом вероятность получения любого числа в основном одинакова.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню