我正在尝试使用单独的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 "", line 1, in 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 " ", line 1, in 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]])
知道我在第一个例子中可能做错了什么吗?
简短的回答:真正的元素的数量m1
和m2
必须匹配,除非其中一人只有一个真正的任期.
还要区分"对角线"索引和"矩形"索引.这是关于索引,而不是切片.尺寸与:
骑行一致.
我可以让你的第一个案例与:
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个"行",而在另一个维度中选择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"行",而最后的第1列,得到的(2,2,1)的形状.其他选择b[:,0,0]
和b[0,2,0]
术语,导致(2,2)形状.(参见我的补遗,为什么两者都只是广播).
这些都是高级索引的情况,包括布尔和数字索引.人们可以研究文档,或者可以玩一下.有时候做这件事会更有趣.:)
(我知道这ix_
对于向np.newaxis
数组添加必要的内容是很好的,所以可以一起广播,但是没有意识到它也适用于布尔数组 - 它用于np.nonzero()
将布尔值转换为索引.)
我认为,这是对两种索引模式的混淆.这可能被称为"对角线"和"矩形"(或逐个元素选择与块选择).为了说明看一个小的2d数组
In [73]: M=np.arange(6).reshape(2,3) In [74]: M Out[74]: array([[0, 1, 2], [3, 4, 5]])
和2个简单的数字索引
In [75]: m1=np.arange(2); m2=np.arange(2)
它们可以使用2种方式:
In [76]: M[m1,m2] Out[76]: array([0, 4])
和
In [77]: M[m1[:,None],m2] Out[77]: array([[0, 1], [3, 4]])
第一顺位选2分,M[0,0]
和M[1,1]
.这种索引让我们挑选出数组的对角线.
第二个选择2行,从那2列.这是对产品进行索引的那种np.ix_
.第一顺位选2分,M[0,0]
和M[1,1]
.这是一种"矩形"索引形式.
更改m2
为3个值:
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
但是如果m2
只有一个元素,我们就不会得到广播错误 - 因为在广播期间可以扩展尺寸1维度:
In [81]: m2=np.arange(1) In [82]: M[m1,m2] Out[82]: array([0, 3])
现在将索引数组更改为boolean,每个数组都匹配相应维度的长度2和3.
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])
使用2和3个True项我们得到一个错误,但是运行2和2或2和1 - 就好像我们使用了True元素的索引:np.nonzero(m2)
.
将此应用于您的示例.在第一个,m1
并m2
有200和299真元素. a[:,m1,m2,:]
由于True术语数量不匹配而失败.
在第二个,它们有2个和1个True项,非零索引为[0,2]
和[0]
,可以广播到[0,0]
.所以它运行.
http://docs.scipy.org/doc/numpy-1.10.0/reference/arrays.indexing.html
解释方面布尔数组索引nonzero
和ix_
.
使用obj.nonzero()类比可以最好地理解组合多个布尔索引数组或布尔与整数索引数组.函数ix_也支持布尔数组,并且可以毫无意外地工作.
进一步思考"对角线"和"块/矩形"索引之间的区别可能更多是我的心理构造numpys
.两者的基础是广播的概念.
拿走n1
和n2
布尔,得到他们的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]])]
一个产生(2,)
阵列,另一个产生(2,1)
.