【问题标题】:NumPy - Faster Operations on Masked Array?NumPy - 屏蔽阵列上的更快操作?
【发布时间】:2020-03-14 16:47:04
【问题描述】:

我有一个 numpy 数组:

import numpy as np
arr = np.random.rand(100)

如果我想找到它的最大值,我会运行 np.amax,它在我的机器上每秒运行 155,357 次。

但是,由于某些原因,我不得不掩盖它的一些价值。例如,让我们只屏蔽一个单元格:

import numpy.ma as ma
arr = ma.masked_array(arr, mask=[0]*99 + [1])

现在,找到最大值要慢得多,每秒运行 26,574 次。

这只是对非屏蔽数组进行此操作的速度的 17%

其他操作,例如,subtractaddmultiply。尽管在掩码数组上,它们对ALL OF THE VALUES 进行运算,但与非掩码数组 (15,343/497,663) 相比,速度只有 4%

我正在寻找一种更快的方法来操作这样的掩码数组,无论它是否使用 numpy。

(我需要在真实数据上运行,即多维数组和数百万个单元格)

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    MaskedArray 是基本 numpy ndarray 的子类。它没有自己的编译代码。详细看numpy/ma/目录,或者主文件:

    /usr/local/lib/python3.6/dist-packages/numpy/ma/core.py
    

    掩码数组必须有关键属性,datamask,一个是您用来创建它的数据数组,另一个是相同大小的布尔数组。

    所以所有操作都必须考虑这两个数组。它不仅要计算新的data,还要计算新的mask

    它可以采取几种方法(取决于操作):

    • 按原样使用data

    • 使用压缩的data - 删除了屏蔽值的新数组

    • 使用填充的data,其中被屏蔽的值被fillvalue 或一些无害的值替换(例如,加法时为0,乘法时为1)。

    屏蔽值的数量(0 或全部)几乎没有区别(如果有的话)。

    因此,您看到的速度差异不足为奇。有很多额外的计算正在进行。 ma.core.py 文件说这个包最初是在 numpy 之前的日子里开发的,并在 2005 年左右被合并到 numpy 中。虽然为了保持最新而进行了一些更改,但我认为它没有经过重大修改。

    这是np.ma.max 方法的代码:

    def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
    
        kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
    
        _mask = self._mask
        newmask = _check_mask_axis(_mask, axis, **kwargs)
        if fill_value is None:
            fill_value = maximum_fill_value(self)
        # No explicit output
        if out is None:
            result = self.filled(fill_value).max(
                axis=axis, out=out, **kwargs).view(type(self))
            if result.ndim:
                # Set the mask
                result.__setmask__(newmask)
                # Get rid of Infs
                if newmask.ndim:
                    np.copyto(result, result.fill_value, where=newmask)
            elif newmask:
                result = masked
            return result
        # Explicit output
        ....
    

    关键步骤是

    fill_value = maximum_fill_value(self)  # depends on dtype
    self.filled(fill_value).max(
                axis=axis, out=out, **kwargs).view(type(self))
    

    您可以使用filled 进行试验,看看您的阵列会发生什么。

    In [40]: arr = np.arange(10.)                                                                                        
    In [41]: arr                                                                                                         
    Out[41]: array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
    In [42]: Marr = np.ma.masked_array(arr, mask=[0]*9 + [1])                                                            
    In [43]: Marr                                                                                                        
    Out[43]: 
    masked_array(data=[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, --],
                 mask=[False, False, False, False, False, False, False, False,
                       False,  True],
           fill_value=1e+20)
    In [44]: np.ma.maximum_fill_value(Marr)                                                                              
    Out[44]: -inf
    In [45]: Marr.filled()                                                                                               
    Out[45]: 
    array([0.e+00, 1.e+00, 2.e+00, 3.e+00, 4.e+00, 5.e+00, 6.e+00, 7.e+00,
           8.e+00, 1.e+20])
    In [46]: Marr.filled(_44)                                                                                            
    Out[46]: array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8., -inf])
    In [47]: arr.max()                                                                                                   
    Out[47]: 9.0
    In [48]: Marr.max()                                                                                                  
    Out[48]: 8.0
    

    【讨论】:

      猜你喜欢
      • 2018-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 2021-08-30
      • 2011-10-11
      • 2016-03-28
      • 1970-01-01
      相关资源
      最近更新 更多