numpy 中有效随机设置矩阵元素

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

Jér*_*ard 5

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)