zeros functions array arange python numpy

python - functions - Traduzca cada elemento en numpy array de acuerdo a la clave



numpy functions (6)

Estoy tratando de traducir cada elemento de numpy.array acuerdo con una clave dada:

Por ejemplo:

a = np.array([[1,2,3], [3,2,4]]) my_dict = {1:23, 2:34, 3:36, 4:45}

Quiero tener:

array([[ 23., 34., 36.], [ 36., 34., 45.]])

Puedo ver cómo hacerlo con un bucle:

def loop_translate(a, my_dict): new_a = np.empty(a.shape) for i,row in enumerate(a): new_a[i,:] = map(my_dict.get, row) return new_a

¿Hay una forma numpy más eficiente y / o pura?

Editar:

Lo sincronicé y el método np.vectorize propuesto por DSM es considerablemente más rápido para matrices más grandes:

In [13]: def loop_translate(a, my_dict): ....: new_a = np.empty(a.shape) ....: for i,row in enumerate(a): ....: new_a[i,:] = map(my_dict.get, row) ....: return new_a ....: In [14]: def vec_translate(a, my_dict): ....: return np.vectorize(my_dict.__getitem__)(a) ....: In [15]: a = np.random.randint(1,5, (4,5)) In [16]: a Out[16]: array([[2, 4, 3, 1, 1], [2, 4, 3, 2, 4], [4, 2, 1, 3, 1], [2, 4, 3, 4, 1]]) In [17]: %timeit loop_translate(a, my_dict) 10000 loops, best of 3: 77.9 us per loop In [18]: %timeit vec_translate(a, my_dict) 10000 loops, best of 3: 70.5 us per loop In [19]: a = np.random.randint(1, 5, (500,500)) In [20]: %timeit loop_translate(a, my_dict) 1 loops, best of 3: 298 ms per loop In [21]: %timeit vec_translate(a, my_dict) 10 loops, best of 3: 37.6 ms per loop In [22]: %timeit loop_translate(a, my_dict)


Aquí hay otro enfoque, usando numpy.unique :

>>> a = np.array([[1,2,3],[3,2,1]]) >>> a array([[1, 2, 3], [3, 2, 1]]) >>> d = {1 : 11, 2 : 22, 3 : 33} >>> u,inv = np.unique(a,return_inverse = True) >>> np.array([d[x] for x in u])[inv].reshape(a.shape) array([[11, 22, 33], [33, 22, 11]])


Asumiendo que las claves dict son enteros positivos, sin grandes huecos (similar a un rango de 0 a N), sería mejor que convirtieras tu traducción dict a una matriz tal que my_array[i] = my_dict[i] , y usando indización numpy para hacer la traducción

Un código que utiliza este enfoque es:

def direct_translate(a, d): src, values = d.keys(), d.values() d_array = np.arange(a.max() + 1) d_array[src] = values return d_array[a]

Prueba con matrices aleatorias:

N = 10000 shape = (5000, 5000) a = np.random.randint(N, size=shape) my_dict = dict(zip(np.arange(N), np.random.randint(N, size=N)))

Para estos tamaños obtengo alrededor de 140 ms para este enfoque. La vectorización np.get toma alrededor de 5.8 s la unique_translate alrededor de 8 s .

Posibles generalizaciones:

  • Si tiene valores negativos para traducir, puede cambiar los valores en ay en las teclas del diccionario por una constante para volver a asignarlos a números enteros positivos:

def direct_translate(a, d): # handles negative source keys min_a = a.min() src, values = np.array(d.keys()) - min_a, d.values() d_array = np.arange(a.max() - min_a + 1) d_array[src] = values return d_array[a - min_a]

  • Si las claves de origen tienen enormes lagunas, la creación inicial de la matriz perdería la memoria. Yo recurriría a cython para acelerar esa función.

Creo que sería mejor iterar sobre el diccionario y establecer valores en todas las filas y columnas "a la vez":

>>> a = np.array([[1,2,3],[3,2,1]]) >>> a array([[1, 2, 3], [3, 2, 1]]) >>> d = {1 : 11, 2 : 22, 3 : 33} >>> for k,v in d.iteritems(): ... a[a == k] = v ... >>> a array([[11, 22, 33], [33, 22, 11]])

Editar:

Si bien puede no ser tan sexy como la respuesta de DSM (realmente buena) usando numpy.vectorize , mis pruebas de todos los métodos propuestos muestran que este enfoque (usando la sugerencia de @ jamylak) es en realidad un poco más rápido:

from __future__ import division import numpy as np a = np.random.randint(1, 5, (500,500)) d = {1 : 11, 2 : 22, 3 : 33, 4 : 44} def unique_translate(a,d): u,inv = np.unique(a,return_inverse = True) return np.array([d[x] for x in u])[inv].reshape(a.shape) def vec_translate(a, d): return np.vectorize(d.__getitem__)(a) def loop_translate(a,d): n = np.ndarray(a.shape) for k in d: n[a == k] = d[k] return n def orig_translate(a, d): new_a = np.empty(a.shape) for i,row in enumerate(a): new_a[i,:] = map(d.get, row) return new_a if __name__ == ''__main__'': import timeit n_exec = 100 print ''orig'' print timeit.timeit("orig_translate(a,d)", setup="from __main__ import np,a,d,orig_translate", number = n_exec) / n_exec print ''unique'' print timeit.timeit("unique_translate(a,d)", setup="from __main__ import np,a,d,unique_translate", number = n_exec) / n_exec print ''vec'' print timeit.timeit("vec_translate(a,d)", setup="from __main__ import np,a,d,vec_translate", number = n_exec) / n_exec print ''loop'' print timeit.timeit("loop_translate(a,d)", setup="from __main__ import np,a,d,loop_translate", number = n_exec) / n_exec

Productos:

orig 0.222067718506 unique 0.0472617006302 vec 0.0357889199257 loop 0.0285375618935


El paquete numpy_indexed (descargo de responsabilidad: soy su autor) proporciona una solución vectorizada elegante y eficiente para este tipo de problema:

import numpy_indexed as npi remapped_a = npi.remap(a, list(my_dict.keys()), list(my_dict.values()))

El método implementado es similar al enfoque mencionado por John Vinyard, pero aún más general. Por ejemplo, los elementos de la matriz no necesitan ser enteros, pero pueden ser de cualquier tipo, incluso los subdramas nd mismos.

Si configura el kwarg ''faltante'' opcional para ''subir'' (el valor predeterminado es ''ignorar''), el rendimiento será ligeramente mejor, y obtendrá un KeyError si no todos los elementos de ''a'' están presentes en las teclas.


No sé acerca de efficient, pero usted podría usar np.vectorize en el .get method of dictionaries:

>>> a = np.array([[1,2,3], [3,2,4]]) >>> my_dict = {1:23, 2:34, 3:36, 4:45} >>> np.vectorize(my_dict.get)(a) array([[23, 34, 36], [36, 34, 45]])


Si realmente no tiene que usar el diccionario como tabla de sustitución, una solución simple sería (para su ejemplo):

a = numpy.array([your array]) my_dict = numpy.array([0, 23, 34, 36, 45]) # your dictionary as array def Sub (myarr, table) : return table[myarr] values = Sub(a, my_dict)

Esto funcionará, por supuesto, solo si los índices de d cubren todos los valores posibles de su a , en otras palabras, solo para los enteros con signo.