2015-01-03 64 views
3

我有兩個numpy數組a,b,其維數爲m乘n。我有一個長度爲n的布爾向量b,我想生成一個新的數組c,它從a,b中選擇n個列,這樣如果b [i]爲真,我從b取出列,否則從a取出列。我如何以最有效的方式做到這一點。我看過select,wherechoose基於布爾向量在numpy中選擇列

+1

你能否提供一些樣品(虛擬)的數據和預期的輸出?我知道你已經很清楚地解釋了它,但它確實幫助其他人(我真的)在視覺上更好地理解你的問題 – Anzel

+0

請忘記我說的話,其他人只是如此善於理解並已經提供解決方案:) – Anzel

回答

4

首先,讓我們設置了一些示例代碼:

import numpy as np 

m, n = 5, 3 
a = np.zeros((m, n)) 
b = np.ones((m, n)) 

boolvec = np.random.randint(0, 2, m).astype(bool) 

只是爲了顯示這個數據可能是什麼樣子:

In [2]: a 
Out[2]: 
array([[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 0., 0., 0.]]) 

In [3]: b 
Out[3]: 
array([[ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.]]) 

In [4]: boolvec 
Out[4]: array([ True, True, False, False, False], dtype=bool) 

在這種情況下,這是最有效的使用np.where此。但是,我們需要boolvec的形狀可以播放與ab相同的形狀。因此,我們可以通過與np.newaxisNone切片(它們是相同的),使之成爲列向量:

In [5]: boolvec[:,None] 
Out[5]: 
array([[ True], 
     [ True], 
     [False], 
     [False], 
     [False]], dtype=bool) 

,然後我們可以使用做了np.where最終結果:

In [6]: c = np.where(boolvec[:, None], a, b) 

In [7]: c 
Out[7]: 
array([[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.]]) 
+0

謝謝, 'where'比'choose'更快。我不需要使用'np。新聞廣播似乎有效? –

+0

@NeilG - 這取決於「boolvec」是「m」長度還是「n」長度。 'np.where'假定與「正常」索引相比略有不同。如果長度爲「m」,則可以使用「boolvec」進行索引,但是「np.where」預計它會廣播,這沿着最後一個軸應用。因此,如果'boolvec'是'm'-長度的,你需要用'np.newaxis'進行切片,如果它是'長'的,你不會(或者說,你可以,但是, d do'boolvec [None,:]')。 –

+0

另外,我剛剛意識到我誤解了你原來的問題。你在問一個'n'長度的矢量,在這種情況下'np.where'按原樣運行。 –

4

你可以爲此使用np.choose

例如ab數組:

>>> a = np.arange(12).reshape(3,4) 
>>> b = np.arange(12).reshape(3,4) + 100 
>>> a_and_b = np.array([a, b]) 

要使用np.choose,我們希望與兩個陣列一個三維陣列; a_and_b看起來是這樣的:

array([[[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11]], 

     [[100, 101, 102, 103], 
     [104, 105, 106, 107], 
     [108, 109, 110, 111]]]) 

現在讓布爾數組是bl = np.array([0, 1, 1, 0])。然後:

>>> np.choose(bl, a_and_b) 
array([[ 0, 101, 102, 3], 
     [ 4, 105, 106, 7], 
     [ 8, 109, 110, 11]]) 
3

計時爲(5000,3000)陣列是:

In [107]: timeit np.where(boolvec[:,None],b,a) 
1 loops, best of 3: 993 ms per loop 

In [108]: timeit np.choose(boolvec[:,None],[a,b]) 
1 loops, best of 3: 929 ms per loop 

In [109]: timeit c=a[:];c[boolvec,:]=b[boolvec,:] 
1 loops, best of 3: 786 ms per loop 

wherechoose基本上是相同的;布爾索引稍快。 select使用choose,所以我沒有時間。


我給列採樣定時是相似的,不同的是這次索引較慢:

In [119]: timeit np.where(cols,b,a) 
1 loops, best of 3: 878 ms per loop 

In [120]: timeit np.choose(cols,[a,b]) 
1 loops, best of 3: 915 ms per loop 

In [121]: timeit c=a[:];c[:,cols]=b[:,cols] 
1 loops, best of 3: 1.25 s per loop 

校正,對於索引我應該使用a.copy()

In [32]: timeit c=a.copy();c[boolvec,:]=b[boolvec,:] 
1 loops, best of 3: 783 ms per loop 
In [33]: timeit c=a.copy();c[:,cols]=b[:,cols] 
1 loops, best of 3: 1.44 s per loop 

我得到Python2.7和3,numpy的1.8.2和1.9.0開發中相同的定時

+0

在我的電腦上選擇速度是原來的兩倍。不知道爲什麼。 –