Numpy系列(十)- 掩码数组
简介
有时候数据集中存在缺失、异常或者无效的数值,我们可以标记该元素为被屏蔽(无效)状态。
import numpy as np import numpy.ma as ma x = np.array([1, 2, 3, -99, 5]) x Out[289]: array([ 1, 2, 3, -99, 5])
现在可以创造一个掩码数组(标记第四个元素为无效状态)。
mx = ma.masked_array(x, mask=[0, 0, 0, 1, 0]) mx Out[291]: masked_array(data=[1, 2, 3, --, 5], mask=[False, False, False, True, False], fill_value=999999)
接下来可以计算平均值而不用考虑无效数据。
mx.mean() Out[292]: 2.75
访问掩码
可通过其mask
属性访问掩码数组的掩码。我们必须记住,掩码中的True
条目表示无效数据。
mx Out[293]: masked_array(data=[1, 2, 3, --, 5], mask=[False, False, False, True, False], fill_value=999999) mx.mask Out[294]: array([False, False, False, True, False])
只访问有效数据
当只想访问有效数据时,我们可以使用掩码的逆作为索引。可以使用numpy.logical_not
函数或简单使用~
运算符计算掩码的逆:
x = ma.array([[1, 2], [3, 4]], mask=[[0, 1], [1, 0]]) x[~x.mask] masked_array(data = [1 4], mask = [False False], fill_value = 999999)
另一种检索有效数据的方法是使用compressed
方法,该方法返回一维ndarray
(或其子类之一,取决于baseclass
属性):
x.compressed() Out[297]: array([1, 4])
修改掩码
通过将True
赋给掩码,可以立即屏蔽数组的所有数据:
x = ma.array([1, 2, 3], mask=[0, 0, 1]) x.mask = True x Out[300]: masked_array(data=[--, --, --], mask=[ True, True, True], fill_value=999999, dtype=int32)
最后,可以通过向掩码分配一系列布尔值来对特定数据条目进行掩码和/或取消掩码:
x = ma.array([1, 2, 3]) x.mask = [0, 1, 0] x Out[303]: masked_array(data=[1, --, 3], mask=[False, True, False], fill_value=999999)
取消掩码
要取消屏蔽一个或多个特定数据条目,我们只需为它们分配一个或多个新的有效值:
x = ma.array([1, 2, 3], mask=[0, 0, 1]) x Out[305]: masked_array(data=[1, 2, --], mask=[False, False, True], fill_value=999999) x[-1] = 5 x Out[307]: masked_array(data=[1, 2, 5], mask=[False, False, False], fill_value=999999)
要取消屏蔽掩码数组的所有掩码条目(假设掩码不是硬掩码),最简单的解决方案是将常量nomask
分配给掩码:
x = ma.array([1, 2, 3], mask=[0, 0, 1]) x Out[309]: masked_array(data=[1, 2, --], mask=[False, False, True], fill_value=999999) x.mask = ma.nomask x Out[311]: masked_array(data=[1, 2, 3], mask=[False, False, False], fill_value=999999)
索引和切片
由于MaskedArray
是numpy.ndarray
的子类,它会继承其用于索引和切片的机制。
当访问没有命名字段的被掩蔽数组的单个条目时,输出是标量(如果掩码的相应条目是False
)或特殊值masked
(如果掩码的相应条目为True
):
x = ma.array([1, 2, 3], mask=[0, 0, 1]) x Out[313]: masked_array(data=[1, 2, --], mask=[False, False, True], fill_value=999999) x[0] Out[314]: 1 x[-1] Out[315]: masked x[-1] is ma.masked Out[316]: True
如果掩蔽的数组具有命名字段,访问单个条目将返回numpy.void
对象(如果没有掩码),或者如果至少一个字段具有与初始数组相同的dtype的0d掩码数组的字段被屏蔽。
y = ma.masked_array([(1,2), (3, 4)],mask=[(0, 0), (0, 1)],dtype=[('a', int), ('b', int)]) y[0] Out[318]: (1, 2) y[-1] Out[319]: (3, --)
当访问切片时,输出是掩蔽的数组,其data
属性是原始数据的视图,并且其掩码是nomask
(如果没有无效条目原始数组)或原始掩码的相应切片的副本。需要复制以避免将掩模的任何修改传播到原始版本。
x = ma.array([1, 2, 3, 4, 5], mask=[0, 1, 0, 0, 1]) mx = x[:3] mx Out[322]: masked_array(data=[1, --, 3], mask=[False, True, False], fill_value=999999) mx[1] = -1 mx Out[324]: masked_array(data=[1, -1, 3], mask=[False, False, False], fill_value=999999) x.mask Out[325]: array([False, False, False, False, True]) x.data Out[326]: array([ 1, -1, 3, 4, 5])
访问具有结构化数据类型的掩蔽数组的字段会返回MaskedArray
。