2011-10-19 63 views
14

爲什麼這個工作:瞭解怪異布爾二維數組索引行爲numpy的

a=np.random.rand(10,20) 
x_range=np.arange(10) 
y_range=np.arange(20) 

a_tmp=a[x_range<5,:] 
b=a_tmp[:,np.in1d(y_range,[3,4,8])] 

,這並不:

a=np.random.rand(10,20) 
x_range=np.arange(10) 
y_range=np.arange(20)  

b=a[x_range<5,np.in1d(y_range,[3,4,8])] 

回答

19

的numpy的參考文檔的page on indexing包含了答案,但需要一點點仔細閱讀。

這裏答案是索引用布爾等價於通過首先用np.nonzero轉化布爾陣列獲得的整數數組索引。因此,布爾數組m1m2

a[m1, m2] == a[m1.nonzero(), m2.nonzero()] 

這(當它成功,即m1.nonzero().shape == m2.nonzero().shape)等價於:

[a[i, i] for i in range(a.shape[0]) if m1[i] and m2[i]] 

我不知道爲什麼它這樣設計的工作 - - 通常,這是而不是你想要什麼。

爲了獲得更直觀的結果,可以改爲做

a[np.ix_(m1, m2)] 

產生相當於

[[a[i,j] for j in range(a.shape[1]) if m2[j]] for i in range(a.shape[0]) if m1[i]] 
+1

這真的沒有意義。我會問在maillist爲什麼這樣。 – tillsten

+1

[scipy.org/Cookbook/Indexing](http://scipy.org/Cookbook/Indexing)p。關於多維布爾索引的14說:「看看numpy的蒙面數組工具......顯而易見的方法並不能給出正確的答案。」 (該文件寫得很好,需要更新。) – denis

+0

@denis,大約在2013年,該文件解釋得相當好。但是,如果您使用Google numpy邏輯索引,那麼出現的文檔是http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html,這一點也沒有解釋清楚。 – John

4

np.ix_的替代方法是布爾數組整數數組轉換結果(使用np.nonzero()),然後使用np.newaxis創建正確形狀的陣列以利用廣播。

import numpy as np 

a=np.random.rand(10,20) 
x_range=np.arange(10) 
y_range=np.arange(20) 

a_tmp=a[x_range<5,:] 
b_correct=a_tmp[:,np.in1d(y_range,[3,4,8])] 

m1=(x_range<5).nonzero()[0] 
m2=np.in1d(y_range,[3,4,8]).nonzero() 
b=a[m1[:,np.newaxis], m2] 
assert np.allclose(b,b_correct) 

b2=a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))] 
assert np.allclose(b2,b_correct) 

np.ix_往往比雙重索引慢。 長形式解看來是快一點:

長式:使用np.ix_

In [85]: %timeit a[x_range<5,:][:,np.in1d(y_range,[3,4,8])] 
10000 loops, best of 3: 144 us per loop 

In [83]: %timeit a[(x_range<5).nonzero()[0][:,np.newaxis], (np.in1d(y_range,[3,4,8])).nonzero()[0]] 
10000 loops, best of 3: 131 us per loop 

雙索引

In [84]: %timeit a[np.ix_(x_range<5,np.in1d(y_range,[3,4,8]))] 
10000 loops, best of 3: 160 us per loop 

注:這將是測試你的機器上的這些時間以來的排名可能會根據你的Python,numpy的,還是硬件的版本中改變一個好主意。