#python #numpy #random
Вопрос:
У меня следующая проблема: я хочу сгенерировать сетку 100х100 ( numpy.ndarray
), заполнив ее числами из заданного списка ( [-1,0,1,2]
). Я хочу распределить их случайным образом по этой сетке. Кроме того, числа должны поддерживать следующие соотношения: число 0 должно занимать 10% сетки, в то время как остальные числа имеют соотношение 30% каждое, поэтому их сумма равна 100%. С помощью np.random.choice()
этого я смог генерировать случайные числа, каждое из которых распределялось с соответствующими вероятностями. Однако у меня возникают проблемы, потому что я должен убедиться, что число 0 составляет ровно 10% от всей сетки, а ненулевые числаровно по 30% каждый. Используя np.random.choice()
функцию, это не всегда так (особенно если размер выборки невелик), потому что я назначил только вероятности, а не соотношения:
import numpy as np
numbers = np.random.choice([-1,0,1,2],(100,100),p=[0.3,0.1,0.3,0.3])
print(np.count_nonzero(numbers)) #must be = 0.1 always!
Другая идея, которая у меня была, состояла в том, чтобы сначала установить всю матрицу как np.zeros((100,100))
, а затем заполнить только 90% ее ненулевыми элементами, однако я не знаю, как подойти к этой проблеме таким образом, чтобы числа распределялись случайным образом по сетке, т. Е. Случайным местоположением/индексом.
Изменить: Соотношение каждого отдельного ненулевого числа в сетке будет зависеть только от того, сколько ячеек я хочу, чтобы они были пустыми, или 0 в этом случае. Все остальные ненулевые элементы должны иметь одинаковое соотношение. Например, я хочу, чтобы 20% сетки были нулями, остальные числа будут иметь соотношение (1 — ratio_of_zero)/amount_of_non-нулевые элементы.
Комментарии:
1. Ключ состоит в том, чтобы создать массив длиной 1D 10000, который имеет правильное число для каждого выбора, а затем np.random.shuffle (). Затем преобразуйте его в массив 100×100.
2. @RemcoGerlich Спасибо, это делает именно то, что я хочу для этого конкретного примера. Однако как я могу сделать это более гибким, т. Е., если количество чисел, которые я хочу распределить, меняется, скажем, в следующий раз, когда мне понадобится 12 чисел в сетке 1000×1000? В этом случае мне нужно было бы применить цикл for, верно? (обратите внимание, что фактическое значение чисел не имеет значения, мне нужно только, чтобы они были различимы)
Ответ №1:
Это должно делать то, что вы хотите (предложено Ремкогерлихом), хотя я не знаю, насколько эффективен этот метод:
import numpy as np
# Constants
SHAPE = (100, 100)
LENGTH = SHAPE[0] * SHAPE[1]
REST = [-1, 1, 2]
ZERO_PROB = 10
BASE_PROB = (100 - ZERO_PROB) // len(REST)
NUM_ZERO = round(LENGTH * (ZERO_PROB / 100))
NUM_REST = round(LENGTH * (BASE_PROB / 100))
# Make base 1D array
base_arr = [0 for _ in range(NUM_ZERO)]
for i in REST:
base_arr = [i for _ in range(NUM_REST)]
base_arr = np.array(base_arr)
# Give it a random order
np.random.shuffle(base_arr)
# Finally, reshape the array
result_arr = base_arr.reshape(SHAPE)
Глядя на ваш комментарий, для гибкости, которая зависит от того, сколько чисел должно иметь разные вероятности, я полагаю. Вы могли бы просто иметь цикл for, который проходит и создает массив нужной длины для каждого, чтобы добавить в base_arr
него . Кроме того, это, конечно, может быть функция, в которую вы передаете переменные, а не просто скрипт с жестко закодированными константами, как это.
Отредактировано на основе комментария.
Комментарии:
1. Соотношение на самом деле будет зависеть только от того, сколько ячеек я хочу, чтобы они были пустыми, или от 0 в случае шляпы. Все остальные ненулевые элементы должны иметь одинаковое соотношение. Скажем, я хочу, чтобы 20% сетки были нулями, остальные числа будут иметь соотношение (1 — ratio_of_zero)/amount_of_non-zero_elements.
2. Я отредактировал его там, основываясь на этом, это больше соответствует тому, что вы хотите?
3. Спасибо вам за такой подход, для меня это прекрасно работает. Это также отражает идею, предложенную @RemcoGerlich, так что спасибо вам обоим. Я также подумал о создании массивов одинаковой длины, но разных значений с помощью цикла for, но затем
np.concatenate
вместо этого использовал их для склеивания. Затем, применивnp.random.schuffle(base_arr)
, я получаю вектор с точными соотношениями, но в случайном порядке. Если кто-то хочет преобразовать в матрицу, его можно просто использоватьnp.reshape()
. При этом эта матрица/сетка также может быть построена, например, сplt.pcolormesh
помощью .