如何正确地对一个numpy的二维数组进行掩码处理?

41

假设我有一个二维坐标数组,看起来像这样

x = array([[1,2],[2,3],[3,4]])

在我的工作中,之前我生成了一个掩码,它看起来像这样

mask = [False,False,True]

当我尝试将此掩码应用于二维坐标向量时,我会得到一个错误

newX = np.ma.compressed(np.ma.masked_array(x,mask))

>>>numpy.ma.core.MaskError: Mask and data not compatible: data size 
   is 6, mask size is 3.`

我想这是有道理的。所以我尝试使用下面的口罩代替:

mask2 = np.column_stack((mask,mask))
newX = np.ma.compressed(np.ma.masked_array(x,mask2))

我得到的结果接近:

>>>array([1,2,2,3])

与我期望(并想要)的接近:

>>>array([[1,2],[2,3]])

一定有更简单的方法吧?

7个回答

27

这是您正在寻找的内容吗?

import numpy as np
x[~np.array(mask)]
# array([[1, 2],
#        [2, 3]])

或者从 NumPy 遮掩数组 中获取:

newX = np.ma.array(x, mask = np.column_stack((mask, mask)))
newX

# masked_array(data =
#  [[1 2]
#  [2 3]
#  [-- --]],
#              mask =
#  [[False False]
#  [False False]
#  [ True  True]],
#        fill_value = 999999)

13

使用 np.where,你可以做很多事情:

x_maskd = np.where(mask, x, 0)

np.where 接受三个参数,一个 conditionxy。这三个参数必须可以广播到相同的形状。在 mask 为 True 的位置返回 x 值,否则返回 y 值。


很少有人理解np.where是一个节省代码行数的好工具! - Artashes

9

您的x为3x2:

In [379]: x
Out[379]: 
array([[1, 2],
       [2, 3],
       [3, 4]])

创建一个由3个布尔元素组成的掩码:

In [380]: rowmask=np.array([False,False,True])

它可以用于选择True或False的行。在两种情况下,结果都是二维的:

In [381]: x[rowmask,:]
Out[381]: array([[3, 4]])

In [382]: x[~rowmask,:]
Out[382]: 
array([[1, 2],
       [2, 3]])

这是不使用MaskedArray子类的情况。要创建这样的数组,我们需要一个与x形状匹配的掩码。目前还没有提供只屏蔽一个维度的功能。

In [393]: xmask=np.stack((rowmask,rowmask),-1)  # column stack

In [394]: xmask
Out[394]: 
array([[False, False],
       [False, False],
       [ True,  True]], dtype=bool)

In [395]: np.ma.MaskedArray(x,xmask)
Out[395]: 
masked_array(data =
 [[1 2]
 [2 3]
 [-- --]],
             mask =
 [[False False]
 [False False]
 [ True  True]],
       fill_value = 999999)

应用compressed函数后,会产生一个扁平化的数组:array([1, 2, 2, 3])
由于遮盖是逐个元素进行的,它可以遮盖一行中的一个元素、两行中的两个元素等。因此,通常情况下,删除被遮盖的元素不会得到二维数组,只能得到扁平化的形式。
当有分散的屏蔽值时,使用np.ma最合适,如果您想选择或取消选整行或整列,则没有太大帮助。
===============
以下是更典型的带有屏蔽数组:
In [403]: np.ma.masked_inside(x,2,3)
Out[403]: 
masked_array(data =
 [[1 --]
 [-- --]
 [-- 4]],
             mask =
 [[False  True]
 [ True  True]
 [ True False]],
       fill_value = 999999)

In [404]: np.ma.masked_equal(x,2)
Out[404]: 
masked_array(data =
 [[1 --]
 [-- 3]
 [3 4]],
             mask =
 [[False  True]
 [ True False]
 [False False]],
       fill_value = 2)

In [406]: np.ma.masked_outside(x,2,3)
Out[406]: 
masked_array(data =
 [[-- 2]
 [2 3]
 [3 --]],
             mask =
 [[ True False]
 [False False]
 [False  True]],
       fill_value = 999999)

3

如果您具备

A =  [[  8.   0. 165.  22. 164.  47. 184. 185.]
      [  0.   6. -74. -27.  63.  49. -46. -48.]
      [165. -74.   0.   0.   0.   0.   0.   0.]
      [ 22. -27.   0.   0.   0.   0.   0.   0.]
      [164.  63.   0.   0.   0.   0.   0.   0.]
      [ 47.  49.   0.   0.   0.   0.   0.   0.]
      [184. -46.   0.   0.   0.   0.   0.   0.]
      [185. -48.   0.   0.   0.   0.   0.   0.]]

你的面罩是

mask = np.array([True, True, True, False, True, False, True, False])

然后您的遮罩 A 就会变成:

A[mask, :][:, mask] = [[  8.   0. 165. 164. 184.]
                       [  0.   6. -74.  63. -46.]
                       [165. -74.   0.   0.   0.]
                       [164.  63.   0.   0.   0.]
                       [184. -46.   0.   0.   0.]]

2

由于这些解决方案都对我没有用,所以我想写下我的解决方案,也许对其他人有用。我使用的是Python 3.x,并且处理了两个3D数组。其中一个我称之为data_3D,包含了脑部扫描中记录的浮点值,另一个template_3D包含代表大脑区域的整数。我想要从data_3D中选择与整数region_code相对应的值,如同template_3D一样:

my_mask = np.in1d(template_3D, region_code).reshape(template_3D.shape)
data_3D_masked = data_3D[my_mask]

这将为我提供一个只包含相关记录的一维数组。


1
在您的最后一个示例中,问题不在于掩码,而在于您对compressed的使用。从compressed的文档字符串中可以看出:
Return all the non-masked data as a 1-D array.

所以compressed将非掩码值压缩成一个一维数组。(必须这样做,因为不能保证压缩数据具有n维结构。)
在压缩之前,请查看掩码数组:
In [8]: np.ma.masked_array(x, mask2)

Out[8]: 
masked_array(data =
 [[1 2]
 [2 3]
 [-- --]],
             mask =
 [[False False]
 [False False]
 [ True  True]],
       fill_value = 999999)

你说得对,在我压缩之前是正确的。我会阅读文档,找到一种方法来删除掩码元素同时保留数组维度。谢谢。 - pretzlstyle
如果我理解你想做的事情,@Psidom的第一个建议看起来是合理的。特别是,你可能不需要一个掩码数组。只需使用布尔数组索引常规数组即可。 - Warren Weckesser

0

masked_X = np.where(mask, X, 0) 是掩码数据的最快和最简单的方法:

X = np.array([[2,-1,4],
              [3,-3,1],
              [9,-7,2]])

mask = np.identity(3)

时间测量:

%timeit np.where(mask,X,0)

969纳秒±14.6纳秒每个循环(7次运行的平均值±标准差,每个循环1000000次)
%timeit np.ma.array(X, mask=mask)

6.47微秒±85.9纳秒每个循环(平均值±7次运行的标准偏差,每个循环100000次)
我让你得出结论!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接