具有多个布尔数组的Numpy多维切片

时间:2016-01-07 03:20:57

标签: python arrays numpy slice

我试图使用单独的1维布尔数组来切割多维数组。出于某种原因,这段代码不起作用:

>>> a = np.ones((100, 200, 300, 2))
>>> a.shape
(100, 200, 300, 2)
>>> m1 = np.asarray([True]*200)
>>> m2 = np.asarray([True]*300)
>>> m2[-1] = False
>>> a[:,m1,m2,:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (200,) (299,) 
>>> m2 = np.asarray([True]*300) # try again with all 300 dimensions True
>>> a[:,m1,m2,:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (200,) (300,) 

但这很好用:

>>> a = np.asarray([[[1, 2], [3, 4], [5, 6]], [[11, 12], [13, 14], [15, 16]]])
>>> a.shape
(2, 3, 2)
>>> m1 = np.asarray([True, False, True])
>>> m2 = np.asarray([True, False])
>>> a[:,m1,m2]
array([[ 1,  5],
       [11, 15]])

对第一个例子中我可能做错了什么的想法?

2 个答案:

答案 0 :(得分:5)

简答:m1m2中的真元素数量必须匹配,除非其中一个元素只有一个True术语。

还要区分对角线&#39;索引和&#39;矩形&#39;索引。这是关于索引,而不是切片。 :的维度就在旅程中。

初步想法

我可以使用第一个案例:

In [137]: a=np.ones((100,200,300,2))

In [138]: m1=np.ones((200,),bool)    
In [139]: m2=np.ones((300,),bool)
In [140]: m2[-1]=False

In [141]: I,J=np.ix_(m1,m2)

In [142]: a[:,I,J,:].shape
Out[142]: (100, 200, 299, 2)

np.ix_将2个布尔数组转换为可广播的索引数组

In [143]: I.shape
Out[143]: (200, 1)
In [144]: J.shape
Out[144]: (1, 299)

请注意,这会选择200行&#39;在一个维度,299在另一个维度。

我不确定为什么在这种情况下需要这种数组的重做,而不是在第二次

In [154]: b=np.arange(2*3*2).reshape((2,3,2))

In [155]: n1=np.array([True,False,True])
In [156]: n2=np.array([True,False])

In [157]: b[:,n1,n2]
Out[157]: 
array([[ 0,  4],      # shape (2,2)
       [ 6, 10]])

采用相同的ix_策略会生成相同的值但形状不同:

In [164]: b[np.ix_(np.arange(b.shape[0]),n1,n2)]
# or I,J=np.ix_(n1,n2);b[:,I,J]
Out[164]: 
array([[[ 0],
        [ 4]],

       [[ 6],
        [10]]])

In [165]: _.shape
Out[165]: (2, 2, 1)

两种情况都使用第一维的所有行。 ix一个选择2行&#39;第二个暗淡,最后一列,产生(2,2,1)形状。另一个选择b[:,0,0]b[0,2,0]项,产生(2,2)形状。 (参见我的补遗,为什么两者都只是广播)。 这些是高级索引的所有情况,包括布尔值和数字索引。人们可以研究文档,或者可以玩一下。有时候做这件事会更有趣。 :)

(我知道ix_对于向数组添加必要的np.newaxis是有好处的,因此可以一起广播,但是没有意识到它也适用于布尔数组 - 它使用{{ 1}}将布尔值转换为索引。)

分辨率

我认为,这是对两种索引模式的混淆。这可能叫做'对角线&#39;和&#39;矩形&#39; (或逐个元素选择与块选择)。为了说明看一个小的2d数组

np.nonzero()

和2个简单的数字索引

In [73]: M=np.arange(6).reshape(2,3)
In [74]: M
Out[74]: 
array([[0, 1, 2],
       [3, 4, 5]])

它们可以使用两种方式:

In [75]: m1=np.arange(2); m2=np.arange(2)

In [76]: M[m1,m2]
Out[76]: array([0, 4])

第一个选择2分,In [77]: M[m1[:,None],m2] Out[77]: array([[0, 1], [3, 4]]) M[0,0]。这种索引让我们可以选择数组的对角线。

第二个选择2行并从那2列中选择。这是M[1,1]生成的索引类型。第一个选择2分,np.ix_M[0,0]。这是一个长方形的&#39;索引的形式。

M[1,1]更改为3个值:

m2

但如果In [78]: m2=np.arange(3) In [79]: M[m1[:,None],m2] # returns a 2x3 Out[79]: array([[0, 1, 2], [3, 4, 5]]) In [80]: M[m1,m2] # produces an error ... ValueError: shape mismatch: objects cannot be broadcast to a single shape 只有一个元素,我们就不会收到广播错误 - 因为在广播期间可以扩展尺寸1尺寸:

m2

现在将索引数组更改为boolean,每个数组都匹配相应维度的长度2和3。

In [81]: m2=np.arange(1)
In [82]: M[m1,m2]
Out[82]: array([0, 3])

使用2和3个真项,我们得到一个错误,但是运行2和2或2和1 - 就好像我们使用了True元素的索引:In [91]: m1=np.ones(2,bool); m2=np.ones(3,bool) In [92]: M[m1,m2] ... ValueError: shape mismatch: objects cannot be broadcast to a single shape In [93]: m2[2]=False # m1 and m2 each have 2 True elements In [94]: M[m1,m2] Out[94]: array([0, 4]) In [95]: m2[0]=False # m2 has 1 True element In [96]: M[m1,m2] Out[96]: array([1, 4])

将此应用于您的示例。在第一个中,np.nonzero(m2)m1有200和299个True元素。 m2由于True术语数量不匹配而失败。

在第二个版本中,他们有2个和1个True术语,非零索引a[:,m1,m2,:][0,2],可以广播到[0]。所以它运行。

http://docs.scipy.org/doc/numpy-1.10.0/reference/arrays.indexing.html 根据{{​​1}}和[0,0]解释布尔数组索引。

  

使用obj.nonzero()类比可以最好地理解组合多个布尔索引数组或布尔与整数索引数组。函数ix_也支持布尔数组,并且可以毫无意外地工作。

附加物

进一步思考&#39;对角线&#39;和&#39;块/矩形&#39;索引可能更像是nonzero的心理结构。两者的基础是广播的概念。

获取ix_numpys布尔值,并获得n1个等价物:

n2

现在尝试在&#39;对角线&#39;和&#39;矩形&#39;模式:

nonzero

一个产生In [107]: n1 Out[107]: array([ True, False, True], dtype=bool) In [108]: np.nonzero(n1) Out[108]: (array([0, 2], dtype=int32),) In [109]: n2 Out[109]: array([ True, False], dtype=bool) In [110]: np.nonzero(n2) Out[110]: (array([0], dtype=int32),) 个数组,另一个产生In [105]: np.broadcast_arrays(np.array([0,2]),np.array([0])) Out[105]: [array([0, 2]), array([0, 0])] In [106]: np.broadcast_arrays(np.array([0,2])[:,None],np.array([0])) Out[106]: [array([[0], [2]]), array([[0], [0]])]

答案 1 :(得分:0)

这可能是一个简单的解决方法:

a[:,m1,:,:][:,:,m2,:]