在numpy中,我可以使用代码
from numpy.random import default_rng
rng = default_rng()
M, N, n = 10000, 1000, 3
rng.choice(np.arange(0, N), size=n, replace=False)
在不替换的情况下,从0到9获得三个随机样本。
我想得到成千上万个这样的随机序列。正确的做法是什么?我知道我能做到
np.array([rng.choice(np.arange(0, N), size=(n,), replace=False) for i in range(0, M)])
但是我想知道是否有更有效的方法来使用Numpy
来实现这一点。
在这个答案中,建议采用以下方法
np.argsort(rng.random((M,N)),axis=1)[:, :n]
这是超快速和优雅的。然而,成本规模像nxm
,而不是我希望实现的nxm
。
还有其他方法吗?
方法#1
对于N
R = np.arange(M)
mask = np.ones((M,N), dtype=bool)
idx = np.random.randint(0,N,(M))
mask[R,idx] = 0
for i in range(1,n):
lim = N-i
m2 = np.ones((M,lim), dtype=bool)
idx2 = np.random.randint(0,lim,(M))
m2[R,idx2] = 0
mask[mask] = m2.ravel()
out = np.nonzero(~mask)[1].reshape(-1,n)
如果您需要随机化每行的数字,请使用问题帖子中链接的兰德技巧:
out = np.take_along_axis(out, np.random.rand(M,n).argsort(1), axis=1)
如果使用m2
创建常量数组让您感到困扰,请在循环前初始化后重新使用,同时保持其余代码不变-
m2 = np.ones((M,N-1), dtype=bool)
for i in range(1,n):
lim = N-i
idx2 = np.random.randint(0,lim,(M))
m2[R,idx2] = 0
mask[mask] = m2.ravel()
m2[R,idx2] = 1
m2 = m2[:,:-1]
方法#2类似于方法#1,但初始化部分的大部分工作是设置每行的unqiue随机数。另一个while
迭代部分负责处理无法分配唯一行的行。使用N
# https://stackoverflow.com/a/51915131/ @Divakar
def random_num_per_grp(L):
# For each element in L pick a random number within range specified by it
r1 = np.random.rand(np.sum(L)) + np.repeat(np.arange(len(L)),L)
offset = np.r_[0,np.cumsum(L[:-1])]
return r1.argsort()[offset] - offset
R = np.arange(M)
mask = np.ones((M,N), dtype=bool)
idx = np.random.randint(0,N,(M,n))
mask[R[:,None],idx] = 0
rows_notdone = mask.sum(1)!=N-n
while np.any(rows_notdone):
idx0 = random_num_per_grp(mask[rows_notdone].sum(1))
steps = np.r_[0,mask.sum(1).cumsum()[:-1]]
flat_idx0 = steps[rows_notdone] + idx0
m2 = np.ones(mask.sum(), dtype=bool)
m2[flat_idx0] = 0
mask[mask] = m2
rows_notdone = mask.sum(1)!=N-n
out = np.nonzero(~mask)[1].reshape(-1,n)