生成numpy数组或随机分布的0和1的最快方法

时间:2018-12-13 12:44:11

标签: python numpy random

我需要为特定的神经网络生成用于辍学的掩码。 我正在寻找使用numpy(仅限CPU)实现此目标的最快方法。

我尝试过:

def gen_mask_1(size, p=0.75):
    return np.random.binomial(1, p, size)


def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

其中p是拥有1

的概率

这两种方法的速度可比。

%timeit gen_mask_1(size=2048)
%timeit gen_mask_2(size=2048)

45.9 µs ± 575 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
47.4 µs ± 372 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

有更快的方法吗?

更新

按照到目前为止的建议,我测试了一些额外的实现。设置@njitparallel=True)时,我无法运行TypingError: Failed in nopython mode pipeline (step: convert to parfors),但是如果没有,它的效率就会降低。 我在这里找到了与英特尔mlk_random的Python绑定(感谢@MatthieuBrucher的提示!):https://github.com/IntelPython/mkl_random 到目前为止,结合使用mlk_random和@nxpnsv的方法可获得最佳效果。

@njit
def gen_mask_3(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

def gen_mask_4(size, p=0.75):
    return (np.random.rand(size) < p).astype(int)

def gen_mask_5(size):
    return np.random.choice([0, 1, 1, 1], size=size)

def gen_mask_6(size, p=0.75):
    return (mkl_random.rand(size) < p).astype(int)

def gen_mask_7(size):
    return mkl_random.choice([0, 1, 1, 1], size=size)

%timeit gen_mask_4(size=2048)
%timeit gen_mask_5(size=2048)
%timeit gen_mask_6(size=2048)
%timeit gen_mask_7(size=2048)

22.2 µs ± 145 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
25.8 µs ± 336 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
7.64 µs ± 133 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
29.6 µs ± 1.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

3 个答案:

答案 0 :(得分:2)

您可以使用Numba编译器,并通过在函数上应用njit装饰器来加快处理速度。以下是一个非常大的size

的示例
from numba import njit

def gen_mask_1(size, p=0.75):
    return np.random.binomial(1, p, size)

@njit(parallel=True)
def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask

%timeit gen_mask_1(size=100000)
%timeit gen_mask_2(size=100000)

2.33 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
512 µs ± 25.1 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

答案 1 :(得分:2)

另一个选项是numpy.random.choice,输入0和1s,其中1s的比例为p。例如,对于p = 0.75,请使用np.random.choice([0, 1, 1, 1], size=n)

In [303]: np.random.choice([0, 1, 1, 1], size=16)
Out[303]: array([1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])

这比使用np.random.binomial更快:

In [304]: %timeit np.random.choice([0, 1, 1, 1], size=10000)
71.8 µs ± 368 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [305]: %timeit np.random.binomial(1, 0.75, 10000)
174 µs ± 348 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

要处理p的任意值,可以使用p的{​​{1}}选项,但是代码比np.random.choice慢:

np.random.binomial

答案 2 :(得分:1)

正如我在评论中说的,问题是实现

def gen_mask_2(size, p=0.75):
    mask = np.random.rand(size)
    mask[mask>p]=0
    mask[mask!=0]=1
    return mask
通过比较,可以改善

,得到一个bool,然后可以将其转换为int。这会删除您原本拥有的带有掩盖分配的两个比较,并且只需要一个衬里即可:)

def gen_mask_2(size, p=0.75):
    return = (np.random.rand(size) < p).astype(int)