为啥 Numpy 掩码数组有用?

Posted

技术标签:

【中文标题】为啥 Numpy 掩码数组有用?【英文标题】:Why are Numpy masked arrays useful?为什么 Numpy 掩码数组有用? 【发布时间】:2019-09-23 01:16:22 【问题描述】:

我一直在阅读掩码数组文档,但我很困惑 - MaskedArray 与仅维护一个值数组和一个布尔掩码有什么不同?有人可以给我一个示例,其中 MaskedArrays 更方便或性能更高吗?

6/5 更新

为了更具体地说明我的问题,这里是一个如何使用 MaskedArray 的经典示例:

>>>data = np.arange(12).reshape(3, 4)
>>>mask = np.array([[0., 0., 1., 0.],
                    [0., 0., 0., 1.],
                    [0., 1., 0., 0.]])

>>>masked = np.ma.array(data, mask=mask)
>>>masked

masked_array(
  data=[[0, 1, --, 3],
        [4, 5, 6, --],
        [8, --, 10, 11]],
  mask=[[False, False,  True, False],
        [False, False, False,  True],
        [False,  True, False, False]],
  fill_value=999999)

>>>masked.sum(axis=0)

masked_array(data=[12, 6, 16, 14], mask=[False, False, False, False], fill_value=999999)

我也可以这样轻松地做同样的事情:

>>>data = np.arange(12).reshape(3, 4).astype(float)
>>>mask = np.array([[0., 0., 1., 0.],
                    [0., 0., 0., 1.],
                    [0., 1., 0., 0.]]).astype(bool)

>>>masked = data.copy()  # this keeps the original data reuseable, as would
                         # the MaskedArray. If we only need to perform one 
                         # operation then we could avoid the copy
>>>masked[mask] = np.nan
>>>np.nansum(masked, axis=0)

array([12.,  6., 16., 14.])

我想 MaskedArray 版本看起来更好一些,如果你需要一个可重用的数组,可以避免复制。从标准 ndarray 转换为 MaskedArray 时,它不会使用同样多的内存吗?并且在将掩码应用于数据时是否避免了引擎盖下的副本?还有其他优势吗?

【问题讨论】:

这与性能无关。我偶尔会看到涉及掩码数组的 SO 问题,但并不多。它们可能在pandas 之前的日子里更有用。 不应该是函数希望写入现有数组中的各种索引并且您希望将其操作限制为值的子集的情况吗? 这是一个使用MaskedArray 屏蔽数组中不需要的部分并利用结果进行绘图的新示例。 ***.com/questions/56411587/… @swatchai 为什么你不能只使用布尔数组来进行屏蔽,而不是使用这个单独的类? @RedPanda MaskedArray 有 2 个部分,数据和掩码,两者具有相同的形状(即相等的行,2D 的列),可以方便地与许多 numpy 的操作一起使用。当需要保留数据部分而使用部分数据(屏蔽数据)时最方便。可以更改掩码而不影响数据。因此,掩码可用于应用其他数组,使一组数组在大小/形状上兼容,并且能够一起使用。这是一个有用的示例(缺少数据案例):currents.soest.hawaii.edu/ocn760_4/_static/masked_arrays.html. 【参考方案1】:

官方回答报here:

理论上,IEEE nan 是专门为解决这个问题而设计的 缺失值,但现实情况是不同平台的行为 不同的是,使生活更加困难。在某些平台上, nan 的存在会使计算速度减慢 10-100 倍。对于整数数据,没有 nan 值存在。

事实上,与类似的 nans 数组相比,掩码数组可能非常慢:

import numpy as np
g = np.random.random((5000,5000))
indx = np.random.randint(0,4999,(500,2))
g_nan = g.copy()
g_nan[indx] = np.nan
mask =  np.full((5000,5000),False,dtype=bool)
mask[indx] = True
g_mask = np.ma.array(g,mask=mask)

%timeit (g_mask + g_mask)**2
1.27 s ± 35.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
(g_nan + g_nan)**2
%timeit (g_nan + g_nan)**2
76.5 ms ± 715 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

什么时候有用?

在多年的编程中,我发现它们在以下场合很有用:

当您想要保留被屏蔽的值以供以后处理,而不复制数组时。 你不想被 nan 操作的奇怪行为所欺骗(顺便说一下you might be tricked by the behaviour of masked array)。 如果掩码是数组的一部分,您必须处理带有掩码的许多数组时,您可以避免代码和混淆。 与 nan 值相比,您可以为掩码值分配不同的含义。例如,我将np.nan 用于缺失值,但我也掩盖了 SNR 较差的值,因此我可以识别两者。

通常,您可以将掩码数组视为更紧凑的表示。最好的方法是逐个测试更易于理解和有效的解决方案。

【讨论】:

感谢您的详尽回答!

以上是关于为啥 Numpy 掩码数组有用?的主要内容,如果未能解决你的问题,请参考以下文章

科学计算基础软件包NumPy入门讲座:掩码数组

通过布尔掩码数组选择numpy数组的元素

Cython 中 numpy 数组掩码的性能

Numpy掩码数组masked arrays,这一篇就够了

如何在 Numpy 中将索引数组转换为掩码数组?

在多个维度上平均 numpy 掩码数组