Вы можете сгенерировать случайное число в [q, p] для каждой строки, а затем установить столько случайных чисел в каждой строке. Если под эффективным вы подразумеваете векторизацию, то да, есть эффективный путь. Хитрость заключается в том, чтобы моделировать выборку без замены по одной оси, но по другой. Это можно сделать с помощью np.argsort
. Вы можете выбрать переменное число индексов, превратив случайный вектор в маску.
def randbin(m, n, p, q):
# output to assign ones into
result = np.zeros((m, n), dtype=bool)
# simulate sampling with replacement in one axis
col_ind = np.argsort(np.random.random(size=(m, n)), axis=1)
# figure out how many samples to take in each row
count = np.random.randint(p, q + 1, size=(m, 1))
# turn it into a mask over col_ind using a clever broadcast
mask = np.arange(n) < count
# apply the mask not only to col_ind, but also the corresponding row_ind
col_ind = col_ind[mask]
row_ind = np.broadcast_to(np.arange(m).reshape(-1, 1), (m, n))[mask]
# Set the corresponding elements to 1
result[row_ind, col_ind] = 1
return result
Выбор сделан таким образом, что каждый прогон равных значений в row_ind
находится между p
и q
элементы длинные. Соответствующие элементы col_ind
уникальны и равномерно распределены в каждой строке.
Альтернативой является @ Prunes solution . Требуется np.argsort
для независимого перемешивания строк, поскольку np.random.shuffle
будет хранить строки вместе:
def randbin(m, n, p, q):
# make the unique rows
options = np.arange(n) < np.arange(p, q + 1).reshape(-1, 1)
# select random unique row to go into each output row
selection = np.random.choice(options.shape[0], size=m, replace=True)
# perform the selection
result = options[selection]
# create indices to shuffle each row independently
col_ind = np.argsort(np.random.random(result.shape), axis=1)
row_ind = np.arange(m).reshape(-1, 1)
# perform the shuffle
result = result[row_ind, col_ind]
return result