2011-11-06 42 views
3

看來我仍然在與the "in" operator in numpy糾纏。這裏的情況:Numpy:檢查多維數組中的元素是否在元組中

>>> a = np.random.randint(1, 10, (2, 2, 3)) 
>>> a 
array([[[9, 8, 8], 
     [4, 9, 1]], 

     [[6, 6, 3], 
     [9, 3, 5]]]) 

我想獲得那些三胞胎第二個元素是(6, 8)的指標。我直覺嘗試的方法是:

>>> a[:, :, 1] in (6, 8) 
ValueError: The truth value of an array with more than one element... 

我的最終目標是在那些位置插入前面的那些乘以2號。使用上面的例子,a應該成爲:

array([[[9, 18, 8], #8 @ pos #2 --> replaced by 9 @ pos #1 by 2 
     [4, 9, 1]], 

     [[6, 12, 3], #6 @ pos #2 --> replaced by 6 @ pos #1 by 2 
     [9, 3, 5]]]) 

預先感謝您爲您的諮詢和時間!

回答

1
import numpy as np 
a = np.array([[[9, 8, 8], 
       [4, 9, 1]], 

       [[6, 6, 3], 
       [9, 3, 5]]]) 

ind=(a[:,:,1]<=8) & (a[:,:,1]>=6) 
a[ind,1]=a[ind,0]*2 
print(a) 

產生

[[[ 9 18 8] 
    [ 4 9 1]] 

[[ 6 12 3] 
    [ 9 3 5]]] 

如果你想在一組不是簡單的範圍檢查會員的話,我喜歡用Python的循環都mac's ideabellamyj's idea使用NP的.in1d。這是更快取決於check_tuple大小:

test.py:

import numpy as np 
np.random.seed(1) 

N = 10 
a = np.random.randint(1, 1000, (2, 2, 3)) 
check_tuple = np.random.randint(1, 1000, N) 

def using_in1d(a): 
    idx = np.in1d(a[:,:,1], check_tuple) 
    idx=idx.reshape(a[:,:,1].shape) 
    a[idx,1] = a[idx,0] * 2 
    return a 

def using_in(a): 
    idx = np.zeros(a[:,:,0].shape,dtype=bool) 
    for n in check_tuple: 
     idx |= a[:,:,1]==n 
    a[idx,1] = a[idx,0]*2 
    return a 

assert np.allclose(using_in1d(a),using_in(a))  

當N = 10,using_in稍快:

% python -m timeit -s'import test' 'test.using_in1d(test.a)' 
10000 loops, best of 3: 156 usec per loop 
% python -m timeit -s'import test' 'test.using_in(test.a)' 
10000 loops, best of 3: 143 usec per loop 

當N = 100時,using_in1d要快得多:

% python -m timeit -s'import test' 'test.using_in1d(test.a)' 
10000 loops, best of 3: 171 usec per loop 
% python -m timeit -s'import test' 'test.using_in(test.a)' 
1000 loops, best of 3: 1.15 msec per loop 
+0

是否有官方numpy的-輔導徽章?如果是的話,你會得到它。:)你有沒有指向在numpy上的一些很好的研究材料?官方的[暫定]教程和參考資料的構成方式使我很難找到我需要的信息......: -/ – mac

+0

順便說一句:這是一個整潔的解決方法,但如果可以使用'in'運算符會更喜歡,因爲在我的「真實情況」中,我有大約10個值的池,不僅是'(6,8)'。 – mac

+0

訣竅不在於你閱讀的內容,而在於你如何閱讀它。對於每個功能,花幾分鐘時間詢問一下, 演示該功能如何運行的簡單示例是什麼?我什麼時候可以用這個?開始構建 一個演示/演示每個功能/概念的示例文件。學習是構建示例文件的副作用。 暫定教程和官方文檔是很好的資源。您可能還會嘗試在[numpy book](http://www.tramy.us/)和 [用戶指南](http://docs.scipy.org/doc/numpy/numpy- user.pdf)。 祝你好運! – unutbu

2

這裏有一個方法可以用於任意長度的元組。它使用numpy.in1d函數。

import numpy as np 
np.random.seed(1) 

a = np.random.randint(1, 10, (2, 2, 3)) 
print(a) 

check_tuple = (6, 9, 1) 

bool_array = np.in1d(a[:,:,1], check_tuple) 
ind = np.where(bool_array)[0] 
a0 = a[:,:,0].reshape((len(bool_array),)) 
a1 = a[:,:,1].reshape((len(bool_array),)) 
a1[ind] = a0[ind] * 2 

print(a) 

和輸出:

[[[6 9 6] 
    [1 1 2]] 

[[8 7 3] 
    [5 6 3]]] 

[[[ 6 12 6] 
    [ 1 2 2]] 

[[ 8 7 3] 
    [ 5 10 3]]] 
+0

有趣的是發現使用'in1d'。它有點冗長(根據轉換的操作數量),但值得嘗試一下! +1 – mac

0

通過unutbu's answer的啓發,我發現了這個可能的解決方案:

>>> l = (8, 6) 
>>> idx = np.zeros((2, 2), dtype=bool) 
>>> for n in l: 
...  idx |= a[:,:,1] == n 
>>> idx 
array([[ True, False], 
     [ True, False]], dtype=bool) 
>>> a[idx] 
array([[9, 8, 8], 
     [6, 6, 3]]) 

它需要知道數組的大小事先調查,雖然。

1

還有一種基於使用查閱表的方法,我從Cellprofiler的一位開發人員那裏學到了。 首先,您需要創建一個查找表(LUT),它的大小是數組中最大的數量。對於每個可能的數組值,LUT具有一個True值或一個假值。 例子:

# create a large volume image with random numbers 
a = np.random.randint(1, 1000, (50, 1000 , 1000)) 
labels_to_find=np.unique(np.random.randint(1,1000,500)) 

# create filter mask LUT 
def find_mask_LUT(inputarr, obs): 
    keep = np.zeros(np.max(inputarr)+1, bool) 
    keep[np.array(obs)] = True 
    return keep[inputarr] 

# This will return a mask that is the 
# same shape as a, with True is a is one of the 
# labels we look for, False otherwise 
find_mask_LUT(a, labels_to_find) 

這工作真快(比np.in1d快得多,而且速度不依賴於對象的數量。)

相關問題