![](/img/trans.png)
[英]Combining slicing and broadcasted indexing for multi-dimensional numpy arrays
[英]Numpy multi-dimensional slicing with multiple boolean arrays
我正在嘗試使用單獨的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]])
知道我在第一個例子中可能做錯了什么嗎?
簡答: m1
和m2
的True元素數必須匹配,除非其中一個只有一個True項。
還要區分“對角線”索引和“矩形”索引。 這是關於索引,而不是切片。 與尺寸:
只是湊湊熱鬧。
我可以讓你的第一個案例與:
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_
產生的索引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個真項,我們得到一個錯誤,但是運行2和2或2和1 - 就好像我們使用了True元素的索引: np.nonzero(m2)
。
將此應用於您的示例。 在第一個中, m1
和m2
有200和299個True元素。 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)
。
這可能是一個簡單的解決方法:
a[:,m1,:,:][:,:,m2,:]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.