2011-02-18 13 views
7

Tengo una gran variedad numpy:Numpy de búsqueda (Mapa o punto)

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

y una variedad de gran ish de valores únicos en un orden particular:

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

Cómo puedo rápidamente (no hay diccionarios de python, no hay copias de A, no hay bucles pitón) reemplazan a los valores en A de manera que se convierten en los índices del de los valores en B:?

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

Me siento muy tonto por no poder hacer esto de la cabeza, ni encontrarlo en la documentación. Puntos fáciles!

Respuesta

6

Aquí tiene

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 

Originalmente me sugirió:

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

Pero me di cuenta que tenía que limitaciones cuando se fue a matrices más grandes. En cambio, los préstamos de @ unutbu la respuesta inteligente:

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

O el de una sola línea

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

que me pareció ser más rápido o más lento que el código de @ unutbu dependiendo del tamaño de las matrices bajo consideración y la cantidad de valores únicos

+0

Esta solución realiza moderadamente rápido para mi caso de uso (B.Size << A.size), pero para el registro, la solución de @ unutbu parece tener un mejor rendimiento general. Sin embargo, ninguno de los dos era una solución "en el lugar" que quizás insinué que quería cuando dije "reemplazar los valores en' A '". ..que no creo que sea posible sin Cython. ¡Gracias a los dos! – Paul

+0

También encontré que la solución de unutbu es generalmente más rápida excepto cuando B.size << A.size. Siempre es divertido ver múltiples soluciones y jugar con la optimización – JoshAdel

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 mantiene los índices en el punto de corte array asociada con cada elemento de A. Tenga en cuenta que tuvimos que ordenar B ya que np.searchsorted espera una matriz ordenada.

index es casi la respuesta deseada, excepto que queremos mapear

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

np.argsort nos ofrece este mapeo:

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]] 

Por lo tanto, como una sola línea, la respuesta es:

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

Llamar a np.sort(B) y np.argsort(B) es ineficaz ya que ambas operaciones equivalen a la clasificación B. Para cualquier 1D-array B,

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

por lo que podemos calcular el resultado deseado un poco más rápido usando

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