Как мне выбрать несколько чисел с разными дистрибутивами?

#python #numpy #random #scipy

#python #numpy #Случайный #scipy

Вопрос:

Допустим, у меня есть собственный пользовательский вектор распределения numpy p .

Тогда p удовлетворяет следующему:

 np.ndim(p) == 1 amp; np.sum(p) == 1 amp; np.all(p >= 0)
 

С помощью этого вектора я могу легко выбрать число [0, p.shape) с помощью np.random.choice(np.arange(len(p)), p=p)

В случае, когда у меня много таких p s, у меня есть матрица (с dim 2) P , которая удовлетворяет:

 np.sum(P[:,i]) == 1   # for all i in P.shape[1]
np.all(P >= 0)
 

Затем я хочу выбрать P.shape[1] числа в диапазоне от 0 до P.shape[0] с вероятностью P.

Например, следующий код:

 P = np.array([[0.2, 0.3],
              [0.5, 0.7],
              [0.3, 0]])
x = np.random.choice(np.arange(P.shape[0], P[:,0]))
y = np.random.choice(np.arange(P.shape[0], P[:,1]))
 

произведет мою волю ( x=0 in 0.2 , x=1 in 0.5 и x=2 in 0.3 и y=0 in 0.3 , y=1 in 0.7 ).

В моем случае P много столбцов, и я хочу выбрать все за один раз.

Конечно, я могу сделать это в цикле for, например:

 random_values = np.empty(P.shape[1])
arange_arr = np.arange(P.shape[0])
for i in range(P.shape[1]):
    random_values[i] = np.random.choice(arange_arr, p=P[:,i])
 

Пытаюсь найти какой-нибудь изящный элегантный способ сделать это.

Ответ №1:

Вы могли бы сделать что-то вроде этого:

 P = np.array([[0.2, 0.3],
              [0.5, 0.7],
              [0.3, 0]])
P_upper = np.cumsum(P, axis=0)
P_lower = np.concatenate((np.zeros((1, P.shape[1])), P_upper[:-1, :]), axis=0)
 

Это создает набор ячеек, которые вы можете оцифровать. Теперь генерируйте случайные числа от 0 до 1:

 r = np.random.rand(10, P.shape[1])
 

Есть несколько способов назначить данные в правильные ячейки. Быстрый и относительно неэффективный способ — использовать логическую маску:

 mask = (r[None, ...] >= P_lower[:, None, :]) amp; (r[None, ...] < P_upper[:, None, :])
result = np.argmax(mask, axis=0)
 

Более эффективный, но более сложный способ — добавить смещение к каждому столбцу и применить np.digitize или np.searchsorted к результату:

 offset = np.arange(P.shape[1])
ind = np.searchsorted((P_upper   offset).ravel('F'), (r   offset).ravel('F')).reshape(r.shape, order='F')
result = ind - offset * P.shape[0]
 

TL; DR

 def multi_sample(p, n):
    ps = np.cumsum(p, axis=0)
    r = np.random.rand(n, ps.shape[1])
    offset = np.arange(P.shape[1])
    ind = np.searchsorted((P_upper   offset).ravel('F'), (r   offset).ravel('F')).reshape(r.shape, order='F')
    return ind - offset * P.shape[0]
 

Комментарии:

1. Спасибо, я надеялся на какую-то встроенную функцию в mupy / scipy .. =

2. @Shaq. Вы можете создать свою собственную служебную функцию. Это не должно быть проблемой. Я добавлю TL; DR

3. Спасибо. Я думаю, что TL; DR может быть лучше в начале ответа, не так ли?