use*_*511 1 python random numpy
我在 numpy 中有一个形状为布尔的矩阵(m, n)。
我将矩阵元素初始化为False。
我想用 value 随机设置每行 ( )中 x的元素。x < nTrue
现在我用循环遍历矩阵,np.random.choice不使用替换:
mat = np.full((M, N), fill_value=False)
for i in range(mat.shape[0]):
mat[i, np.random.choice(mat.shape[1], x, replace=False)] = True
Run Code Online (Sandbox Code Playgroud)
有没有更有效的方法来做到这一点numpy?
np.random.choice当要选取的值的数量与数组的大小相比较小时,效果不是最佳的。这是因为当前的实现使用分区方法。更快的实现包括选择一些随机位置,然后检查是否存在重复项并重复此过程,直到所有位置都不同(当x/N非常小时,这很可能(当 时x/N < 0.05,每次迭代生成正确数字的概率 >0.95) .Numba 可以加速这个过程。下面是生成的代码:
import numba as nb
@nb.njit('(int_, int_, int_[::1])')
def pick(x, N, out):
assert out.size == x
if x / N <= 0.05:
while True:
for j in range(x):
out[j] = np.random.randint(0, N)
out.sort()
ok = True
for i in range(x-1):
if out[i] == out[i+1]:
ok = False
if ok: return
out[:] = np.random.choice(N, x, replace=False)
@nb.njit('bool_[:,::1](int_, int_, int_)')
def compute(M, N, x):
mat = np.zeros((M, N), dtype=np.bool_)
cols = np.empty(x, np.int_)
for i in range(M):
pick(x, N, cols)
for j in cols:
mat[i, j] = True
return mat
N, M = 1000, 1000
x = 10
mat = compute(M, N, x)
Run Code Online (Sandbox Code Playgroud)
一种更快、更简单的方法是按照 Kelly Bundy 的建议直接设置数组中的值。这是避免缓慢排序操作的好处。这是生成的代码:
import numba as nb
@nb.njit('bool_[:,::1](int_, int_, int_)')
def compute(M, N, x):
mat = np.zeros((M, N), dtype=np.bool_)
for i in range(M):
if x/N <= 0.20:
k = 0
while k < x:
j = np.random.randint(0, N)
if not mat[i, j]:
mat[i, j] = True
k += 1
else:
for j in np.random.choice(N, x, replace=False):
mat[i, j] = True
return mat
N, M = 1000, 1000
x = 10
mat = compute(M, N, x)
Run Code Online (Sandbox Code Playgroud)
这比我的机器上的初始方法快 276 倍,也比其他答案快得多。
Initial: 27.61 ms
Salvatore D.B.: 20.54 ms
D.Manasreh: 14.90 ms
Numba V1: 0.66 ms
Numba V2: 0.10 ms <---
Run Code Online (Sandbox Code Playgroud)