Получение массива из np случайного выбора, избегающего циклов и ошибки «a должен быть одномерным»

#python #numpy #loops #for-loop #random

#python #numpy #циклы #для цикла #Случайный

Вопрос:

Я пытаюсь найти способ получить массив значений из np.random.choise, используя матрицу значений и одну из вероятностей, без использования циклов.

Представьте, что у меня есть что-то вроде этого

 vals=  array([[ 0.        ,  1.22222222,  2.44444444,  3.66666667,  4.88888889,
         6.11111111,  7.33333333,  8.55555556,  9.77777778, 11.        ],
       [ 3.        ,  8.22222222, 13.44444444, 18.66666667, 23.88888889,
        29.11111111, 34.33333333, 39.55555556, 44.77777778, 50.        ]])

probs= array([[0.01056171, 0.15521083, 0.07796945, 0.09986356, 0.14516427,
        0.12496125, 0.00091384, 0.19739258, 0.00088116, 0.18708136],
       [0.01220221, 0.17791623, 0.13682813, 0.05679157, 0.16599396,
        0.09769565, 0.09365478, 0.15176203, 0.0965629 , 0.01059253]])
  

как я могу получить массив, эквивалентный этому

 [np.random.choice(vals[i],p=probs[i]) for i in range(len(probs))]

out[1]: 
[6.111111111111112, 23.88888888888889]
  

без использования цикла for??

Я ожидал, что np.random.choice будет транслировать матрицы по строкам, но я получаю ошибку «a должен быть одномерным».

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

1. Вы просто хотели этого или серьезно ожидали этого, основываясь на чтении документов?

Ответ №1:

Я заметил, что сумма вероятностей по строкам составляет всего 1,0, поэтому нормализация не требуется.

Чтобы вычислить ваш результат, определите следующую функцию:

 def rndFromRows(arr, probs):
    rowIdx = np.arange(arr.shape[0])
    colIdx = (probs.cumsum(1) > np.random.rand(probs.shape[0])[:,None]).argmax(1)
    return arr[(rowIdx, colIdx)]
  

Или более краткая версия:

 def rndFromRows(arr, probs):
    return arr[(np.arange(arr.shape[0]), (probs.cumsum(1) >
        np.random.rand(probs.shape[0])[:,None]).argmax(1))]
  

Затем вычислите результат как:

 np.random.seed(0)    # To get a repeatable result
result = rndFromRows(vals, probs)
  

Я сравнил время выполнения, используя%timeit и обнаружил, что мой код выполняется
примерно в 5 раз быстрее, чем ваш. Сравните самостоятельно.

Результат:

 array([ 6.11111111, 34.33333333])
  

Конечно, в окончательной версии вашего кода удалите заполнение генератора
случайных чисел.