Numpy Lookup (Map, or Point)
Here you go
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
Originally I suggested:
D = np.choose(C,ii).reshape(A.shape)
But I realized that that had limitations when you went to larger arrays. Instead, borrowing from @unutbu's clever reply:
D = np.argsort(B)[C].reshape(A.shape)
Or the one-liner
np.argsort(B)[np.digitize(A.reshape(-1,),np.sort(B)) - 1].reshape(A.shape)
Which I found to be faster or slower than @unutbu's code depending on the size of the arrays under consideration and the number of unique values.
import numpy as npA=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
holds the indices into the array cutoff associated with each element of A
. Note we had to sort B
since np.searchsorted
expects a sorted array.
index
is almost the desired answer, except that we want to map
1-->13-->00-->32-->2
np.argsort
provides us with this mapping:
print(np.argsort(B))# [3 1 2 0]print(np.argsort(B)[1])# 1print(np.argsort(B)[3])# 0print(np.argsort(B)[0])# 3print(np.argsort(B)[2])# 2print(np.argsort(B)[index])# [[1 1 0 3 2]# [0 2 3 2 1]# [2 2 0 0 1]# [3 3 1 2 0]]
So, as a one-liner, the answer is:
np.argsort(B)[np.sort(B).searchsorted(A)]
Calling both np.sort(B)
and np.argsort(B)
is inefficient since both operations amount to sorting B
. For any 1D-array B
,
np.sort(B) == B[np.argsort(B)]
So we can compute the desired result a bit faster using
key=np.argsort(B)result=key[B[key].searchsorted(A)]