при условии, что k
будет намного меньше, чем n
, вы можете реализовать выборку без замены самостоятельно:
idx = np.random.randint([5,4,3], size=[5,3])
idx[:,2:] += idx[:,2:] >= idx[:,1,None]
idx[:,1:] += idx[:,1:] >= idx[:,0,None]
np.array([1,2,3,4,5])[arr]
, вставив в функцию, это может быть:
def sample_noreplace(arr, n, k):
assert k <= len(arr)
idx = np.random.randint(len(arr) - np.arange(k), size=[n, k])
for i in range(k-1, 0, -1):
idx[:,i:] += idx[:,i:] >= idx[:,i-1,None]
return np.array(arr)[idx]
для запуска sample_noreplace([1,2,3,4,5], 10000, 3)
требуется ~ 1 мс, в то время как для кода OP требуется ~ 800 мс
, чтобы показать, что выборка выполняется равномерно, и в таблицу были бы выведены большие объемы:
arr = sample_noreplace(range(5), 1_000_000, 3)
# summarise
dict(zip(*np.unique(arr, return_counts=True)))
который дает мне: {0: 600288, 1: 599656, 2: 600494, 3: 599233, 4: 600329}
, который выглядит довольно равномерно. затем мы можем проверить в каждой позиции:
out = np.zeros([3, 5])
for i in range(3):
n, c = np.unique(arr[:,i], return_counts=True)
out[i, n] = c
, что дает мне таблицу, похожую на:
array([[199936., 199701., 200106., 199843., 200414.],
[200227., 200044., 200345., 199897., 199487.],
[200125., 199911., 200043., 199493., 200428.]])
, которая также выглядит равномерно.