numpy ndarray的身份掩码

问题描述

我希望True在用作遮罩时会保留ndarray,但是,它会像None一样增加尺寸。

arr = np.arange(16).reshape(2,4,2)
np.all(arr[True] == arr)         # outputs: True

足够接近,但看起来更近:

arr[True].shape                  # outputs: (1,2,2)
arr[None].shape                  # outputs: (1,2)

我发现了两种设置身份掩码的方法:使用slice(None)Ellipsis

np.all(arr[slice(None)] == arr)  # outputs: True
arr[slice(None)].shape           # outputs: (2,2)

np.all(Ellipsis == arr)          # outputs: True
arr[Ellipsis].shape              # outputs: (2,2)

这里没有什么真正令人惊讶的,因为这首先就是切片的工作方式。 slice(None)有点丑陋,而Ellipsis似乎有点快。
但是,请执行以下操作:

我不确定我是否完全理解这一点:

从1.15.0版开始不推荐使用:为了保持与Numeric中的常用用法向后兼容,如果选择对象是包含切片的任何非ndarray和非元组序列(例如列表),则也将启动基本切片对象,省略号对象或newaxis对象,但不适用于整数数组或其他嵌入式序列。

我知道保留数组的最佳方法不是屏蔽它,而是说我真的想为屏蔽设置认值...;-)

问题: 设置身份掩码的首选方法是什么?如果可以的话,True是否添加尺寸是预期的行为?

解决方法

对于示例二维数组:

In [172]: x=np.array([[1,2],[4,3]])
In [173]: x.__array_interface__
Out[173]: 
{'data': (50806320,False),'strides': None,'descr': [('','<i8')],'typestr': '<i8','shape': (2,2),'version': 3}

带有省略号的视图:

In [174]: x[...].__array_interface__
Out[174]: 
{'data': (50806320,# same as for x
 'strides': None,'version': 3}

具有附加尺寸的视图:

In [175]: x[None].__array_interface__
Out[175]: 
{'data': (50806320,'shape': (1,2,'version': 3}

具有附加尺寸的副本-注意更改数据地址。高级索引。

In [176]: x[True].__array_interface__
Out[176]: 
{'data': (50796640,'version': 3}

另一个尺寸为0的副本。它正在重用内存。

In [177]: x[False].__array_interface__
Out[177]: 
{'data': (50796640,'shape': (0,'version': 3}

indexing页上唯一可以找到的参考是:

https://numpy.org/doc/stable/reference/arrays.indexing.html#detailed-notes

布尔数组的非零等价不适用于零维布尔数组。

如果这种行为是过去的实现遗留下来的,我不会感到惊讶。由于合并多个数字包的历史,因此存在一些粗糙的边缘。其中一些已经或正在弃用。

标量布尔索引是zero dimensional boolean array

In [178]: np.array(True).shape
Out[178]: ()

我们可以在以下位置添加新维度:

In [181]: x[:,True].shape
Out[181]: (2,1,2)
In [183]: x[...,False].shape
Out[183]: (2,0)
,

您一直在说“掩码”,但听起来根本就不需要掩码操作,即使是“身份”掩码也是如此。遮罩数组通常是形状与原始数组相同的布尔数组,使用遮罩进行索引将生成一维数组,其中包含由遮罩选择的项。即使是完全真实的蒙版,也可以生成应用于它的阵列的平坦副本。这不是身份操作。可以使用遮罩来做奇怪的事情,但是不能执行身份操作。

如果您希望索引器输出与原始数组等效的数组,则典型的,最通用的方法是...-文字省略号:

arr[...]

:不同,这也适用于0维数组。请注意,这将生成一个视图,而不是副本。没有索引器可以产生副本并在所有输入尺寸下正常工作。


arr[True]的工作方式与主要是出于使0维数组遵循与正维数组遵循相同的布尔索引规则的愿望类似。如上所述,如果使用n维掩码对n维数组进行索引,则结果将是1维数组。如果使用0维掩码对0维数组建立索引,结果将再次为1维数组:

In [1]: import numpy

In [2]: x = numpy.array([[1,[3,4]])

In [3]: x[x % 2 == 0]
Out[3]: array([2,4])

In [4]: y = numpy.array([1,3,4])

In [5]: y[y % 2 == 0]
Out[5]: array([2,4])

In [6]: z = numpy.array(5) # 0-dimensional!

In [7]: z[z % 2 == 0]
Out[7]: array([],dtype=int64)

In [8]: z[z % 2 == 1]
Out[8]: array([5])

使用0维掩码对0维数组进行索引会使维数增加1。一般来说,使用0维掩码对n维数组进行索引会产生n + 1维数组。如果蒙版为True,则额外尺寸的长度为1;否则为0。如果mask为False,则额外维度的长度为0,并且输出中没有元素。这种一般性的行为很少有用,但最适合(极有用)的规则,该规则将正尺寸蒙版应用于尺寸不匹配的数组。