Ошибка распределения случайного выбора Numpy


У меня есть список чисел и другой список вероятностей, который соответствует этим числам. Я использую numpy.random.choice для создания случайного 2d массива:

choice = numpy.random.choice([10, 22, 30], [10, 10], p=[0.45, 0.45, 0.10])

В choice должно быть 45 единиц, 45 двоек и 10 нулей, но после нескольких запусков я никогда не получаю правильное распределение.

unique, counts = numpy.unique(choice, return_counts=True)
print(dict(zip(unique, counts)))

{10: 49, 22: 37, 30: 14}
{10: 47, 22: 42, 30: 11}
{10: 40, 22: 51, 30: 9}

Что я пропустил?

4 2

4 ответа:

То есть, если вы бросите монету тысячу раз, вы ожидаете, что всегда получите ровно 500 голов?

Если вы хотите контролировать точное количество каждого результата, вы не можете полагаться на вероятности-вместо этого выберите (без замены) из списка, в котором каждый результат присутствует с желаемой кратностью:
numpy.random.choice([10] * 45 + [22] * 45 + [30] * 10, [10, 10], replace=False)

Вы полностью упускаете из виду, как выборка из распределения работает на практике. Вы никогда не "получаете" правильное распределение, вы всегда получаете приближение к нему, потому что вы делаете выборку.

Только в том случае, когда число выборок очень велико, вы должны в конечном итоге сходиться к целевому распределению. Но так как выборка-это стохастический процесс, то в результатах этого процесса всегда присутствует случайность.

И это, конечно, относится к генерации чисел с a (псевдо-)генератор случайных чисел.

То, что сказал Матиас, - правда.

Если вы хотите создать массив с ровно 45 нулями, 45 единицами и 10 двойками, с формой (10, 10), но в случайном порядке, вы можете сделать что-то вроде этого:

import numpy as np
zeros = np.array([0]*45)
ones = np.array([1]*45)
twos = np.array([2]*10)
myarr = np.concatenate([zeros, ones, twos])

# Random permutation, followed by reshaping in (10, 10) form
choice = np.random.permutation(myarr).reshape(10,10)
unique, counts = np.unique(choice, return_counts=True)
print(dict(zip(unique, counts)))
{0: 45, 1: 45, 2: 10}

Выборка не будет точной, вы можете заставить все числа быть в выходном массиве, составив список всех чисел, которые вы хотите, а затем случайным образом перемешать его:

import numpy
import numpy.random

numbers = numpy.asarray(45*[10]+45*[22]+10*[30])
print (numbers)
numpy.random.shuffle(numbers) # numbers is changed in place
choice = numbers.reshape((10,10))

print (choice)
unique, counts = numpy.unique(choice, return_counts=True)
print(dict(zip(unique, counts)))