【问题标题】:python fancy indexing with a boolean masked arraypython花式索引与布尔掩码数组
【发布时间】:2016-11-22 03:19:25
【问题描述】:

我有一个 numpy 掩码的数据数组:

data = masked_array(data = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --],
                    mask = [False True False False False True False False True True False True True False True])

我有一个特定类型数据的标志,它是一个布尔掩码数组:

flag = masked_array(data = [True False False True -- -- -- False -- True -- -- -- -- True],
                    mask = [False False False False True True True False True False True True True True False])

我想做类似data[flag] 的事情并得到以下输出:

output_wanted = [7 1 -- --]

对应于标志为 True 的数据元素。相反,我得到了这个:

output_real = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --]

为了更清楚,我没有复制输出的掩码。

我不介意输出带有标志大小的输出,只要它选择我想要的数据(对应于标志的 True 值的数据)。但我无法弄清楚为什么它会在实际输出中给出这些值!

【问题讨论】:

    标签: python numpy indexing masked-array


    【解决方案1】:

    如果我重建你的数组:

    In [28]: d=np.ma.masked_equal([7,0,7,1,8,0,1,1,0,0,3,0,0,3,0],0)
    
    In [29]: f=np.ma.MaskedArray([True,False,False,True, False,False,False,False,True,True,True,True,True,True,True],[False, False, False, False, True, True, True, False, True, False, True, True, True, True, False])
    
    In [30]: d
    Out[30]: 
    masked_array(data = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --],
                 mask = [False  True False False False  True False False  True  True False  True
      True False  True],
           fill_value = 0)
    
    In [31]: f
    Out[31]: 
    masked_array(data = [True False False True -- -- -- False -- True -- -- -- -- True],
                 mask = [False False False False  True  True  True False  True False  True  True
      True  True False],
           fill_value = True)
    

    蒙面显示匹配,但我猜蒙面值是什么。

    In [32]: d[f]
    Out[32]: 
    masked_array(data = [7 1 -- -- 3 -- -- 3 --],
                 mask = [False False  True  True False  True  True False  True],
           fill_value = 0)
    
    In [33]: d[f.data]
    Out[33]: 
    masked_array(data = [7 1 -- -- 3 -- -- 3 --],
                 mask = [False False  True  True False  True  True False  True],
           fill_value = 0)
    

    索引f 与使用data 属性索引相同。它的面具什么也没做。显然我的掩码值与你的不同。

    但如果我使用 filled 数组进行索引,我会得到所需的数组:

    In [34]: d[f.filled(False)]
    Out[34]: 
    masked_array(data = [7 1 -- --],
                 mask = [False False  True  True],
           fill_value = 0)
    

    fillednp.ma 代码中被大量使用,根据np 操作具有不同的填充值(例如,0 表示 sum v 1 表示产品)。掩码数组通常不会遍历它们的值而跳过掩码数组;相反,他们将屏蔽的值转换为无害的值,并使用常规的 numpy 操作。另一种策略是使用compressed 删除屏蔽值。

    indices = np.where(flag.filled(False)) 在另一个答案中被提及,但普通的布尔形式也可以。

    掩码数组具有datamask 属性。屏蔽不会直接更改 data 值。该任务留给filled 之类的方法。

    【讨论】:

    • 这让我觉得是一个错误,甚至允许使用屏蔽数组进行索引,因为这样做似乎破坏了填充值无关紧要的屏蔽数组的语义。我希望会有if isinstance(boolmask, MaskedArray) and getmask(boolmask) is not False: raise ValueError 或其他东西
    • 索引是通过将indx 元组传递给d.__getitem__ 方法来实现的。如果d 是一个掩码数组,它会将任务委托给d.data[indx]d.mask[indx]indx 元组可以有切片、标量、列表、数组等。从这样的元组中阻止屏蔽数组将需要大量额外的逻辑——不仅是屏蔽数组索引。 np.arange(15)[f]?
    【解决方案2】:

    我弄清楚了使用掩码数组进行索引的工作原理。

    其实python并不处理这种索引。

    当使用flag 一个布尔掩码数组执行data[flag] 之类的操作时,python 会获取flag 的基础数据。换句话说,它在被屏蔽之前获取被屏蔽值的值。

    因此请注意:如果掩码值没有明确地用它们的fill_value 填充,则索引可能看起来是随机的。

    例子:

    >>> arr = np.array([0, 1, 2, 3, 4])
    >>> flag = np.ma.masked_array([True, False, False, True, True],
                                  [False, True, False, False, True])
    
    >>> arr[flag])
    array([0, 3, 4])
    

    一种方法就像 jedwards answer。

    但我认为应该避免使用掩码数组来标记数据,它不会带来足够的洞察力。

    如果是用于访问特定类型数据的标志数组,则应将掩码值设置为False。例如,如果您想插入未标记的数据。

    如果标志数组用于屏蔽某种类型的数据,屏蔽值应设置为True。

    【讨论】:

    • data[flag[~flag.mask]] 不会像您预期的那样工作,原因有两个。第一个是 flag[~flag.mask] 返回一个整数数组,而不是您需要的布尔值(请参阅我的帖子的更新 2)。第二个是数组的长度,即使强制为布尔值,也会太小,过滤不正确的元素。在我的 numpy 版本中,尝试此操作会显示 VisibileDeprecationWarning 通知我长度差异。
    • 是的,我在测试时注意到了长度问题。但是为什么flag[~flag.mask] 会返回一个 int 数组??
    【解决方案3】:

    类似的东西呢:

    import numpy as np
    from numpy.ma import masked_array
    
    data = masked_array(data = [7,     0,     7,     1,     8,     0,    1,     1,     0,    0,     3,     0,    0,    3,     0],
                        mask = [False, True,  False, False, False, True, False, False, True, True,  False, True, True, False, True])
    flag = masked_array(data = [True,  False, False, True,  0,     0,    0,     False, 0,    True,  0,     0,    0,    0,     True],
                        mask = [False, False, False, False, True,  True, True,  False, True, False, True,  True, True, True,  False])
    
    print(repr(data))
    print(repr(flag))
    
    indices = np.where(flag & ~flag.mask)
    print(data[indices])
    

    请注意,如果 flag 中的屏蔽值无法与 & 进行比较,您可能会遇到麻烦,但您的情况似乎并非如此。

    输出:

    masked_array(数据 = [7 -- 7 1 8 -- 1 1 -- -- 3 -- -- 3 --], 掩码 = [假真假假假真假假真真假真真假真], 填充值 = 999999) masked_array(数据 = [1 0 0 1 -- -- -- 0 -- 1 -- -- -- -- 1], 掩码 = [假假假假真真真假真假真真真真假], 填充值 = 999999) [7 1 -- --]

    编辑:

    获取索引的另一种方法也可能是:

    indices = np.where(flag.filled(False))
    

    更新(编辑 2):

    注意使用数组索引数组的微妙之处。

    考虑以下代码:

    import numpy as np
    
    data = np.array([1,2,3,4,5])
    mask = np.array([True, False, True, False, True])
    
    res  = data[mask]
    print(res)
    

    正如您可能(或可能不会)期望的那样,在这里,掩码充当“过滤器”,过滤掉掩码中相应位置为 False 的数据元素。由于我为datamask 选择了值,因此索引用于过滤掉偶数data 值,只留下奇数。

    这里的输出是:[1 3 5]

    现在,考虑非常相似的代码:

    import numpy as np
    
    data = np.array([1,2,3,4,5])
    mask = np.array([1, 0, 1, 0, 1])
    
    res  = data[mask]
    print(res)
    

    这里,唯一改变的是掩码元素的数据类型,它们的布尔值是相同的。我们称第一个掩码(由True/False 值组成)mask1 和第二个掩码(由1/0 值组成)mask2

    您可以通过dtype 属性检查数组的数据类型(例如print(mask.dtype))。 mask1 的数据类型为bool,而mask2 的数据类型为int32

    但是,这里的输出不同: [2 1 2 1 2]

    这是怎么回事?

    事实上,索引的行为取决于用于索引的数组的数据类型。如前所述,当“掩码”的数据类型为布尔值时,它具有过滤功能。但是当“掩码”的数据类型是整数时,它提供“选择”功能,使用索引的元素作为原始数组的索引。

    因此,在第二个示例中,由于 data[1] = 2data[0] = 1data[mask2] 的结果是长度为 5 的数组,而不是 3(在布尔情况下)。

    换一种说法,给定以下代码:

    res = data[mask]
    

    如果mask.dtype == int,res的长度将等于mask的长度。

    如果mask.dtype == bool,res的长度将等于掩码中True值的个数。

    差别很大。

    最后,您可以使用astype 方法将一种数据类型的数组强制转换为另一种数据类型。

    演示sn-p:

    import numpy as np
    
    data = np.array([1,2,3,4,5])
    
    # Create a boolean mask
    mask1 = np.array([True, False, True, False, True])
    
    # Create an integer "mask", using the same logical values 
    mask2 = np.array([1,0,1,0,1])
    
    # Coerce mask2 into a boolean mask
    mask3 = mask2.astype(bool)
    
    print(data)         # [1 2 3 4 5]
    print("-" * 80)
    print(mask1)        # [True  False  True  False  True]
    print(mask1.dtype)  # bool
    print(data[mask1])  # [1 3 5]
    print("-" * 80)
    print(mask2)        # [1 0 1 0 1]
    print(mask2.dtype)  # int32
    print(data[mask2])  # [2 1 2 1 2]
    print("-" * 80)
    print(mask3)        # [True  False  True  False  True]
    print(mask3.dtype)  # bool
    print(data[mask3])  # [1 3 5]
    

    【讨论】:

    • 是的,谢谢。但是你知道当给定一个布尔掩码数组时python是如何处理索引的吗?我不明白输出
    猜你喜欢
    • 2020-01-14
    • 1970-01-01
    • 2020-02-14
    • 2019-11-04
    • 2021-03-09
    • 2019-10-29
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    相关资源
    最近更新 更多