繁体   English   中英

NumPy - 屏蔽数组上的更快操作?

[英]NumPy - Faster Operations on Masked Array?

我有一个 numpy 数组:

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

如果我想找到它的最大值,我会运行np.amax ,它在我的机器上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 进行操作,但与非掩码数组相比,速度仅为4% (15,343/497,663)

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM