problemas de operaciones de mallas de malla

Y, X = np.mgrid[-3:-3:10j, -3:3:10j] 

Me he dado cuenta de que al aplicar ciertas operaciones en meshgrids como la que aparece arriba, recibo un error porque es posible que las operaciones no sean compatibles con numpy. A veces puede haber una alternativa de función numpy para el pecado, porque no para todas las funciones como la función quad en scipy.integrate.

¿Cómo puedo solucionar este problema? Necesito aplicar operaciones en todos los meshgrids.

Su pregunta (con el comentario de seguimiento) se puede tomar al menos de dos maneras diferentes:

  1. Tiene una función de múltiples argumentos, y le gustaría poder llamar a esa función de una manera que sea sintácticamente similar a las llamadas difundidas admitidas de forma nativa por números. El rendimiento no es el problema, solo la syntax de llamada de la función.

  2. Tiene una función de múltiples argumentos que se evaluará en una secuencia de matrices numpy, pero la función no se implementa de tal manera que pueda explotar la disposición de memoria contigua de las matrices numpy. El rendimiento es el problema; le encantaría hacer un bucle en las matrices numpy y llamar a su función en un estilo aburrido y simple para el bucle for, excepto que hacerlo es demasiado lento.

Para el artículo 1, hay una función de conveniencia proporcionada por numpy llamada vectorize que toma un llamamiento regular y devuelve un llamable que puede llamarse con arreglos de numpy como argumentos y obedecerá las reglas de transmisión de numpy.

Considere este ejemplo artificial:

 def my_func(x, y): return x + 2*y 

Ahora supongamos que necesito evaluar esta función en todas partes en una cuadrícula 2D. Aquí está la forma aburrida y simple:

 Y, X = np.mgrid[0:10:1, 0:10:1] Z = np.zeros_like(Y) for i in range(Y.shape[0]): for j in range(Y.shape[1]): Z[i,j] = my_func(X[i,j], Y[i,j]) 

Si tuviéramos algunas funciones diferentes como my_func , sería bueno generalizar este proceso en una función que “asignó” una función dada sobre las matrices de 2-D.

 import itertools def array_map(some_func, *arg_arrays): output = np.zeros_like(arg_arrays[0]) coordinates = itertools.imap(range, output.shape) for coord in itertools.product(coordinates): args = [arg_array[coord] for arg_array in arg_arrays] output[coord] = some_func(*args) return output 

Ahora podemos ver que array_map(my_func, X, Y) actúa como el bucle for nested:

 In [451]: array_map(my_func, X, Y) Out[451]: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21], [14, 15, 16, 17, 18, 19, 20, 21, 22, 23], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25], [18, 19, 20, 21, 22, 23, 24, 25, 26, 27]]) 

Ahora, ¿no sería bueno si pudiéramos llamar array_map(my_func) y dejar de lado los argumentos adicionales de la matriz? En lugar de eso, simplemente recupera una nueva función que estaba esperando para hacer los bucles for necesarios.

Podemos hacer esto con functools.partial , por lo que podemos escribir un pequeño vectorizador práctico como este:

 import functools def vectorizer(regular_function): awesome_function = functools.partial(array_map, regular_function) return awesome_function 

y probándolo

 In [453]: my_awesome_func = vectorizer(my_func) In [454]: my_awesome_func(X, Y) Out[454]: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21], [14, 15, 16, 17, 18, 19, 20, 21, 22, 23], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25], [18, 19, 20, 21, 22, 23, 24, 25, 26, 27]]) 

¡Ahora my_awesome_func comporta como si pudieras llamarlo directamente sobre ndarrays!

He pasado por alto muchos pequeños detalles adicionales de rendimiento, verificación de límites, etc., al hacer esta versión de juguete llamada vectorizer … pero afortunadamente, en muchos lugares hay vectorize que ya hace exactamente esto.

 In [455]: my_vectorize_func = np.vectorize(my_func) In [456]: my_vectorize_func(X, Y) Out[456]: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], [ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21], [14, 15, 16, 17, 18, 19, 20, 21, 22, 23], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25], [18, 19, 20, 21, 22, 23, 24, 25, 26, 27]]) 

Una vez más, como subrayé en mis comentarios anteriores al OP y en la documentación para vectorize , esto no es una optimización de velocidad. De hecho, la función adicional de sobrecarga de llamadas será más lenta en algunos casos que solo escribir un for-loop directamente. Pero, para los casos en que la velocidad no es un problema, este método le permite hacer que sus funciones personalizadas se adhieran a las mismas convenciones de llamadas que numpy, lo que puede mejorar la uniformidad de la interfaz de su biblioteca y hacer que el código sea más consistente y más legible.

Ya se ha escrito un montón de otras cosas sobre el elemento 2. Si su problema es que necesita optimizar sus funciones para aprovechar bloques de memoria contiguos y pasar por la comprobación dinámica de tipos (las características principales que las matrices numpy agregan a las listas de Python ) entonces aquí hay algunos enlaces que pueden ser útiles:

  1. < http://pandas.pydata.org/pandas-docs/stable/enhancingperf.html >
  2. < http://csl.name/C-functions-from-Python/ >
  3. < https://jakevdp.github.io/blog/2014/05/09/why-python-is-slow >