2015-12-11 64 views
3

有一些關於numpy.where()我不明白:使用numpy.where()通過矩陣迭代

比方說,我有一個2D numpy的ndarray:

import numpy as np 
twodim = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 1, 1, 12], [17, 3, 15, 16], [17, 3, 18, 18]]) 

現在,想創建一個函數,它可以「檢查」這個numpy數組的各種條件。

array([[ 1, 2, 3, 4], 
     [ 1, 6, 7, 8], 
     [ 1, 1, 1, 12], 
     [17, 3, 15, 16], 
     [17, 3, 18, 18]]) 

例如,哪些條目此數組中有(A)的偶數(B)比7(C)被3整除更大?

我想用numpy.where()這一點,並遍歷該陣列的每個條目,終於找到符合所有條件,(如果這樣的條目存在)的元素:

even_entries = np.where(twodim % 2 == 0) 
    greater_seven = np.where(twodim > 7) 
    divisible_three = np.where(twodim % 3 == 0) 

怎樣才能做到這一點?我不知道如何通過布爾迭代...

我可以通過

np.argwhere(even_entries) 

我們可以做這樣的事情

import numpy as np 
twodim = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 1, 1, 12], [17, 3, 15, 16], [17, 3, 18, 18]]) 
even_entries = np.where(twodim % 2 == 0) 
greater_seven = np.where(twodim > 7) 
divisible_three = np.where(twodim % 3 == 0) 
for row in even_entries: 
    for item in row: 
     if item: #equivalent to `if item == True` 
       for row in greater_seven: 
        for item in row: 
         if item: #equivalent to `if item == True` 
          for row in divisible_three: 
           for item in row: 
            if item: #equivalent to `if item == True` 
             # something like print(np.argwhere()) 

任何訪問性基質(i,j)的指數建議?

編輯1:下面的好主意。正如@hpaulj提到「你的測試產生了一個與twodim形狀相同的布爾矩陣」 這是我在玩的時候遇到的一個問題---並非所有的條件都產生了與我的起始矩陣相同形狀的矩陣。舉例來說,假設我比較數組元素是否具有匹配陣列向左或向右(即水平)

twodim[:, :-1] == twodim[:, 1:] 

這導致在(5,3)布爾數組,而我們原來的矩陣一個(5,4)陣列

array([[False, False, False], 
     [False, False, False], 
     [ True, True, False], 
     [False, False, False], 
     [False, False, True]], dtype=bool) 

如果我們做同樣的垂直,其導致一個(4,4)布爾數組,而原始矩陣是(5,4)

twodim[:-1] == twodim[1:] 

array([[ True, False, False, False], 
     [ True, False, False, False], 
     [False, False, False, False], 
     [ True, True, False, False]], dtype=bool) 

如果我們想知道哪些條目hav Ë縱向和橫向對,這是不平凡弄清楚我們是在哪個維度

+0

不要使用'where'。我不知道爲什麼新的NumPy用戶繼續使用它,但它不是一個好主意。您可以通過直接使用布爾模板來簡化操作。 – user2357112

回答

1

你的測試產生相同形狀的布爾矩陣爲twodim

In [487]: mask3 = twodim%3==0 
In [488]: mask3 
Out[488]: 
array([[False, False, True, False], 
     [False, True, False, False], 
     [False, False, False, True], 
     [False, True, True, False], 
     [False, True, True, True]], dtype=bool) 

至於其他的答案中提到,你可以邏輯地組合試驗 - 用and和or。

np.wherenp.nonzero(在此使用中)相同,只是返回True值的座標 - 作爲2個數組的元組。

In [489]: np.nonzero(mask3) 
Out[489]: 
(array([0, 1, 2, 3, 3, 4, 4, 4], dtype=int32), 
array([2, 1, 3, 1, 2, 1, 2, 3], dtype=int32)) 

argwhere返回相同的值,但作爲一個轉置二維數組。

In [490]: np.argwhere(mask3) 
Out[490]: 
array([[0, 2], 
     [1, 1], 
     [2, 3], 
     [3, 1], 
     [3, 2], 
     [4, 1], 
     [4, 2], 
     [4, 3]], dtype=int32) 

無論是masktuple可以用來直接索引你的陣列:

In [494]: twodim[mask3] 
Out[494]: array([ 3, 6, 12, 3, 15, 3, 18, 18]) 
In [495]: twodim[np.nonzero(mask3)] 
Out[495]: array([ 3, 6, 12, 3, 15, 3, 18, 18]) 

argwhere不能直接用於索引,但可能更適合於反覆,特別是如果你想索引以及值:

In [496]: for i,j in np.argwhere(mask3): 
    .....:  print(i,j,twodim[i,j]) 
    .....:  
0 2 3 
1 1 6 
2 3 12 
3 1 3 
3 2 15 
4 1 3 
4 2 18 
4 3 18 

where相同的東西需要一個zip

for i,j in zip(*np.nonzero(mask3)): print(i,j,twodim[i,j]) 

但一般在numpy我們儘量避免重複。如果你可以直接使用twodim[mask],你的代碼會更快。

布爾口罩的邏輯組合更容易產生比where指數的組合。要使用索引,我可能會採用set操作(聯合,相交,差異)。


至於縮小尺寸的測試,你必須決定如何映射到原始數組(和其他測試)。例如

A(5,3)掩模(列之間的差異):

In [505]: dmask=np.diff(twodim, 1).astype(bool) 
In [506]: dmask 
Out[506]: 
array([[ True, True, True], 
     [ True, True, True], 
     [False, False, True], 
     [ True, True, True], 
     [ True, True, False]], dtype=bool) 

它可以索引原始陣列的3列

In [507]: twodim[:,:-1][dmask] 
Out[507]: array([ 1, 2, 3, 1, 6, 7, 1, 17, 3, 15, 17, 3]) 
In [508]: twodim[:,1:][dmask] 
Out[508]: array([ 2, 3, 4, 6, 7, 8, 12, 3, 15, 16, 3, 18]) 

它也可以被結合的另一3列面膜:

In [509]: dmask & mask3[:,:-1] 
Out[509]: 
array([[False, False, True], 
     [False, True, False], 
     [False, False, False], 
     [False, True, True], 
     [False, True, False]], dtype=bool) 

它仍然比更容易測試的布爾數組形式相結合指數。

+0

@ hpaulj 「你的測試產生相同的形狀twodim的布爾矩陣」 這是我遇到我的玩具圍繞一個問題---不是所有的條件語句產生矩陣相同的形狀,我的出發矩陣。請參閱編輯 – ShanZhengYang

+0

上面的評論我添加了你的例子。 – hpaulj

+0

謝謝。有些東西我仍然沒有遵循上面的內容。我們的原始矩陣是(5,4),'dmask'是(5,3)。我們的組合最終面罩不應該成形(5,4)嗎?行之間的區別是什麼呢,這是形狀(4,4)。因此,要知道哪些條目有橫向合作伙伴和垂直合作伙伴。什麼是「最後的面具」? – ShanZhengYang

0

如果你想找到所有三個條件都滿足:

import numpy as np 
twodim = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 1, 1, 12], [17, 3, 15, 16], [17, 3, 18, 18]]) 

mask = (twodim % 2 == 0) & (twodim > 7) & (twodim % 3 =0) 

print(twodim[mask]) 

[12 18 18] 

不知道你最終是否希望行中的所有元素都必須滿足條件並找到這些行或者是否需要單個元素。

+0

我很樂意這樣做。不幸的是,當我在上面編輯時,很難在特定的條件下創建這樣的蒙版。這些尺寸不能一起廣播。 – ShanZhengYang

+1

@ShanZhengYang:然後,只需切出的重疊部分爲'&'在一起,或者在創建的掩模的過程中執行分片(所以'twodim [適當:件]> 7')。試圖處理'where'輸出將會變得更慢更尷尬。 – user2357112

0
import numpy as np 
twodim = np.array([[1, 2, 3, 4], [1, 6, 7, 8], [1, 1, 1, 12], [17, 3, 15, 16], [17, 3, 18, 18]]) 
condition = (twodim % 2. == 0.) & (twodim > 7.) & (twodim % 3. ==0.) 
location = np.argwhere(condition == True) 


for i in location: 
    print i, twodim[i[0],i[1]], 

>>> [2 3] 12 [4 2] 18 [4 3] 18