Вот подход с np.random.choice
для перетасовки индексов, затем заполнение этих индексов повторениями вставленных целых. Он заполнит массив в точных пропорциях, которые вы укажете:
import numpy as np
np.random.seed(444)
board = np.zeros(50 * 50, dtype=np.uint8).flatten()
# The "20% cells with 0" can be ignored since that is the default.
#
# This will work as long as the proportions are "clean" ints
# (I.e. mod to 0; 2500 * 0.2 is a clean 500. Otherwise, need to do some rounding.)
rpt = (board.shape[0] * np.array([0.3, 0.3, 0.2])).astype(int)
repl = np.repeat([1, 2, 3], rpt)
idx = np.random.choice(board.shape[0], size=repl.size, replace=False)
board[idx] = repl
board = board.reshape((50, 50))
Результирующие частоты:
>>> np.unique(board, return_counts=True)
(array([0, 1, 2, 3], dtype=uint8), array([500, 750, 750, 500]))
>>> board
array([[1, 3, 2, ..., 3, 2, 2],
[0, 0, 2, ..., 0, 2, 0],
[1, 1, 1, ..., 2, 1, 0],
...,
[1, 1, 2, ..., 2, 2, 2],
[1, 2, 2, ..., 2, 1, 2],
[2, 2, 2, ..., 1, 0, 1]], dtype=uint8)
подход
Свести доску. Проще работать с индексами, когда доска (временно) одномерна.
rpt
- это 1-й вектор числа повторений на целое число. Он «упакован» вместе с [1, 2, 3]
для создания repl
, длина которого составляет 2000. (80% от размера доски; вам не нужно беспокоиться о 0 в этом примере.)
Индексы уплощенного массива эффективно перетасовываются (idx
), а длина этого перетасованного массива ограничена размером кандидатов на замену. Наконец, эти индексы на 1-й доске заполнены заменами, после чего их можно снова сделать 2-мя.