【问题标题】:Why is creating a masked numpy array so slow with mask=None or mask=0为什么使用 mask=None 或 mask=0 创建一个带掩码的 numpy 数组这么慢
【发布时间】:2016-05-26 18:03:15
【问题描述】:

今天我分析了一个函数,发现了一个(至少对我而言)奇怪的瓶颈:使用mask=Nonemask=0 创建一个掩码数组以初始化一个全零但与data 形状相同的掩码是很慢:

>>> import numpy as np
>>> data = np.ones((100, 100, 100))

>>> %timeit ma_array = np.ma.array(data, mask=None, copy=False)
1 loop, best of 3: 803 ms per loop

>>> %timeit ma_array = np.ma.array(data, mask=0, copy=False)
1 loop, best of 3: 807 ms per loop

另一方面,使用mask=False 或手动创建蒙版要快得多:

>>> %timeit ma_array = np.ma.array(data, mask=False, copy=False)
1000 loops, best of 3: 438 µs per loop

>>> %timeit ma_array = np.ma.array(data, mask=np.zeros(data.shape, dtype=bool), copy=False)
1000 loops, best of 3: 453 µs per loop

为什么给None0Falsenp.zeros(data.shape) 慢近2000 倍作为mask 参数?鉴于function docs 只说它:

必须可转换为与数据具有相同形状的布尔数组。 True 表示被屏蔽(即无效)的数据。

我在 Windows 10 上使用 python 3.5、numpy 1.11.0

【问题讨论】:

  • 你挖到numpy代码了吗?

标签: python performance numpy


【解决方案1】:

mask=FalseNumPy 1.11.0 source code 中是特例:

if mask is True and mdtype == MaskType:
    mask = np.ones(_data.shape, dtype=mdtype)
elif mask is False and mdtype == MaskType:
    mask = np.zeros(_data.shape, dtype=mdtype)

mask=0mask=None 走慢路,制作一个 0 维掩码数组并通过 np.resize 调整大小。

【讨论】:

  • resizea = concatenate((a,)*n_copies)
【解决方案2】:

我相信@user2357112 有解释。我分析了这两种情况,结果如下:

In [14]: q.run('q.np.ma.array(q.data, mask=None, copy=False)')
         49 function calls in 0.161 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        3    0.000    0.000    0.000    0.000 :0(array)
        1    0.154    0.154    0.154    0.154 :0(concatenate)
        1    0.000    0.000    0.161    0.161 :0(exec)
       11    0.000    0.000    0.000    0.000 :0(getattr)
        1    0.000    0.000    0.000    0.000 :0(hasattr)
        7    0.000    0.000    0.000    0.000 :0(isinstance)
        1    0.000    0.000    0.000    0.000 :0(len)
        1    0.000    0.000    0.000    0.000 :0(ravel)
        1    0.000    0.000    0.000    0.000 :0(reduce)
        1    0.000    0.000    0.000    0.000 :0(reshape)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        5    0.000    0.000    0.000    0.000 :0(update)
        1    0.000    0.000    0.161    0.161 <string>:1(<module>)
        1    0.000    0.000    0.161    0.161 core.py:2704(__new__)
        1    0.000    0.000    0.000    0.000 core.py:2838(_update_from)
        1    0.000    0.000    0.000    0.000 core.py:2864(__array_finalize__)
        5    0.000    0.000    0.000    0.000 core.py:3264(__setattr__)
        1    0.000    0.000    0.161    0.161 core.py:6119(array)
        1    0.007    0.007    0.161    0.161 fromnumeric.py:1097(resize)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:128(reshape)
        1    0.000    0.000    0.000    0.000 fromnumeric.py:1383(ravel)
        1    0.000    0.000    0.000    0.000 numeric.py:484(asanyarray)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.161    0.161 profile:0(q.np.ma.array(q.data, mask=None, copy=False))

In [15]: q.run('q.np.ma.array(q.data, mask=False, copy=False)')
         37 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(array)
        1    0.000    0.000    0.000    0.000 :0(exec)
       11    0.000    0.000    0.000    0.000 :0(getattr)
        1    0.000    0.000    0.000    0.000 :0(hasattr)
        5    0.000    0.000    0.000    0.000 :0(isinstance)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        5    0.000    0.000    0.000    0.000 :0(update)
        1    0.000    0.000    0.000    0.000 :0(zeros)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 core.py:2704(__new__)
        1    0.000    0.000    0.000    0.000 core.py:2838(_update_from)
        1    0.000    0.000    0.000    0.000 core.py:2864(__array_finalize__)
        5    0.000    0.000    0.000    0.000 core.py:3264(__setattr__)
        1    0.000    0.000    0.000    0.000 core.py:6119(array)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.000    0.000 profile:0(q.np.ma.array(q.data, mask=False, copy=False))

所以看来,数组的拼接步骤是瓶颈。

【讨论】:

    猜你喜欢
    • 2018-03-04
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2020-10-28
    相关资源
    最近更新 更多