2012-08-08 44 views
4

比方說,我在形式numpy.searchsorted與多個源

a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6] 
b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1] 

兩個數組正如你所看到的,上面列進行排序,認爲ab作爲超級陣列的列時。

現在,我想對這個數組做個搜索。舉例來說,如果我搜索(3,7),(A = 3,B = 7),我應該得到6

每當有在a重複值,搜索應該值繼續b

有沒有一個內置的numpy方法來做到這一點?或者,假設我在數組中有一百萬個條目,那麼有效的方法是什麼呢?

我嘗試用numpy.recarray,創建一個與ab重新陣列,並試圖在其中搜索,但我收到以下錯誤。

TypeError: expected a readable buffer object 

任何幫助,非常感謝。

+0

b實際上並沒有排序 – 2012-08-08 16:15:44

回答

3

你快到了。這只是numpy.record(這是我假設你使用的,鑑於你收到的錯誤信息)並不是你想要的;只需創建一個項目記錄陣列:

>>> a_b = numpy.rec.fromarrays((a, b)) 
>>> a_b 
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9), 
     (4, 4), (4, 8), (5, 1), (6, 1)], 
     dtype=[('f0', '<i8'), ('f1', '<i8')]) 
>>> numpy.searchsorted(a_b, numpy.array((3, 7), dtype=a_b.dtype)) 
6 

這也可能是有用的詞彙知道sortargsort排序記錄陣列,並且也有lexsort。使用lexsort一個例子:

>>> random_idx = numpy.random.permutation(range(12)) 
>>> a = numpy.array(a)[random_idx] 
>>> b = numpy.array(b)[random_idx] 
>>> sorted_idx = numpy.lexsort((b, a)) 
>>> a[sorted_idx] 
array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]) 
>>> b[sorted_idx] 
array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]) 

排序記錄數組:

>>> a_b = numpy.rec.fromarrays((a, b)) 
>>> a_b[a_b.argsort()] 
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9), 
     (4, 4), (4, 8), (5, 1), (6, 1)], 
     dtype=[('f0', '<i8'), ('f1', '<i8')]) 
>>> a_b.sort() 
>>> a_b 
rec.array([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (3, 4), (3, 7), (3, 9), 
     (4, 4), (4, 8), (5, 1), (6, 1)], 
     dtype=[('f0', '<i8'), ('f1', '<i8')]) 
+0

完美!我只是錯過了。謝謝! – 2012-08-08 21:52:29

4

你可以使用重複searchsorted從左右:

left, right = np.searchsorted(a, 3, side='left'), np.searchsorted(a, 3, side='right') 
index = left + np.searchsorted(b[left:right], 7) 
+1

我打算髮布相同的..(我更喜歡使用一個命名的參數,它側面讀取更好imo' side ='right''。) – 2012-08-08 16:16:05

+0

是的,這的確讀得更好;謝謝。 – ecatmur 2012-08-08 16:17:24

+0

+1它適合我 – 2012-08-08 16:30:41

0

ñ陣列擴展:

import numpy as np 

def searchsorted_multi(*args): 
    v = args[-1] 
    if len(v) != len(args[:-1]): 
     raise ValueError 
    l, r = 0, len(args[0]) 
    ind = 0 
    for vi, ai in zip(v, args[:-1]): 
     l, r = [np.searchsorted(ai[l:r], vi, side) for side in ('left', 'right')] 
     ind += l 
    return ind 

if __name__ == "__main__": 
    a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6] 
    b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1] 
    c = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 2] 

    assert(searchsorted_multi(a, b, (3, 7)) == 6) 
    assert(searchsorted_multi(a, b, (3, 0)) == 5) 
    assert(searchsorted_multi(a, b, c, (6, 1, 2)) == 12) 
+0

如果'b'中不存在'7',則失敗。 – ecatmur 2012-08-08 16:13:04

+0

確實。替換我的答案由另一個版本啓發你:) – 2012-08-08 16:29:59

0

這裏有一個有趣的方式來做到這一點(雖然這不是最有效的方法,如我相信它是O(n)而不是O(log(n)),因爲ecatmur的答案是這樣;但它更緊湊):

np.searchsorted(a + 1j*b, a_val + 1j*b_val) 

例如:

>>> a = np.array([0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6]) 
>>> b = np.array([1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1]) 
>>> np.searchsorted(a + 1j*b, 4 + 1j*8) 
9 
0

或者不numpy的:

>>> import bisect 
>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6] 
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1] 
>>> bisect.bisect_left(zip(a,b), (3,7)) 
6 
1

這個工作對我來說:

>>> a = [0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 6] 
>>> b = [1, 2, 1, 2, 1, 4, 7, 9, 4, 8, 1, 1] 
>>> Z = numpy.array(zip(a, b), dtype=[('a','int'), ('b','int')]) 
>>> Z.searchsorted(numpy.asarray((3,7), dtype=Z.dtype)) 
6 

我想招可能是要確保搜索排序的參數與數組具有相同的dtype。當我嘗試Z.searchsorted((3, 7))時,我收到段錯誤。