2011-02-18 40 views
7

我有一個大numpy的數組:NumPy的查找(地圖,或點)

array([[32, 32, 99, 9, 45], # A 
     [99, 45, 9, 45, 32], 
     [45, 45, 99, 99, 32], 
     [ 9, 9, 32, 45, 99]]) 

,並以特定的順序大十歲上下排列的唯一值:

array([ 99, 32, 45, 9])  # B 

如何快速(沒有python字典,沒有A的副本,沒有python循環)替換A中的值,以便成爲B中的值的標記?:

array([[1, 1, 0, 3, 2], 
     [0, 2, 3, 2, 1], 
     [2, 2, 0, 0, 1], 
     [3, 3, 1, 2, 0]]) 

我覺得無法做到這一點從頭開始,也沒有在文檔中找到它。簡單點!

回答

6

在這裏你去

A = array([[32, 32, 99, 9, 45], # A 
    [99, 45, 9, 45, 32], 
    [45, 45, 99, 99, 32], 
    [ 9, 9, 32, 45, 99]]) 

B = array([ 99, 32, 45, 9]) 

ii = np.argsort(B) 
C = np.digitize(A.reshape(-1,),np.sort(B)) - 1 

本來我建議:

D = np.choose(C,ii).reshape(A.shape) 

但我意識到,這有其侷限性,當你去到更大的陣列。相反,從@ unutbu借貸很聰明的回答:

D = np.argsort(B)[C].reshape(A.shape) 

還是一個班輪

np.argsort(B)[np.digitize(A.reshape(-1,),np.sort(B)) - 1].reshape(A.shape) 

我發現比@ unutbu的代碼更快或更慢取決於陣列所考慮的尺寸和唯一值的數量。

+0

該解決方案適度更快我的用例(B.size << A.size執行),但爲了記錄,@ unutbu的解決方案似乎具有更好的綜合性能。然而,我也沒有提到「就地」解決方案,當我說「替換'A'中的值時,我可能只是暗示需要。 ..我不認爲沒有Cython是可能的。謝謝你們兩位! – Paul 2011-02-22 01:52:09

7
import numpy as np 
A=np.array([[32, 32, 99, 9, 45], 
      [99, 45, 9, 45, 32], 
      [45, 45, 99, 99, 32], 
      [ 9, 9, 32, 45, 99]]) 

B=np.array([ 99, 32, 45, 9]) 

cutoffs=np.sort(B) 
print(cutoffs) 
# [ 9 32 45 99] 

index=cutoffs.searchsorted(A) 
print(index) 
# [[1 1 3 0 2] 
# [3 2 0 2 1] 
# [2 2 3 3 1] 
# [0 0 1 2 3]]  

index保持指數成具有A每個元素相關聯的陣列截止。請注意,我們必須排序B,因爲np.searchsorted需要排序的數組。

index幾乎是所期望的答案,但我們要映射

1-->1 
3-->0 
0-->3 
2-->2 

np.argsort爲我們提供了這個映射:

print(np.argsort(B)) 
# [3 1 2 0] 
print(np.argsort(B)[1]) 
# 1 
print(np.argsort(B)[3]) 
# 0 
print(np.argsort(B)[0]) 
# 3 
print(np.argsort(B)[2]) 
# 2 

print(np.argsort(B)[index]) 
# [[1 1 0 3 2] 
# [0 2 3 2 1] 
# [2 2 0 0 1] 
# [3 3 1 2 0]] 

所以,作爲一個班輪,得到的答覆是:

np.argsort(B)[np.sort(B).searchsorted(A)] 

調用np.sort(B)np.argsort(B)效率低下,因爲這兩個操作相當於排序B。對於任何一維數組B

np.sort(B) == B[np.argsort(B)] 

因此,我們可以計算出所需的結果有點快使用

key=np.argsort(B) 
result=key[B[key].searchsorted(A)]