Alternativa más rápida al uso de la función `map`

Tengo una función f , por ejemplo:

 def f(x): return x**2 

y desea obtener una matriz que consiste en f evaluada en un intervalo, por ejemplo, el intervalo unitario (0,1). Podemos hacer esto de la siguiente manera:

 import numpy as np X = np.arange(0,1,0.01) arr = np.array(list(map(f, X))) 

Sin embargo, esta última línea consume mucho tiempo cuando la función es complicada (en mi caso involucra algunas integrales). ¿Hay una manera de hacerlo más rápido? Estoy feliz de tener una solución no elegante: el enfoque está en la velocidad.

Si f es tan complicado que no puede expressse en términos de operaciones de matriz comstackdas y solo puede tomar escalas, he descubierto que frompyfunc ofrece el mejor rendimiento (aproximadamente 2 frompyfunc comparación con un bucle explícito)

 In [76]: def f(x): ...: return x**2 ...: In [77]: foo = np.frompyfunc(f,1,1) In [78]: foo(np.arange(4)) Out[78]: array([0, 1, 4, 9], dtype=object) In [79]: foo(np.arange(4)).astype(int) Out[79]: array([0, 1, 4, 9]) 

Devuelve el objeto dtype, por lo que necesita un astype . np.vectorize usa esto, pero es un poco más lento. Ambos generalizan a varias formas de matrices de entrada.

Para un resultado de fromiter trabaja con parte del map (sin la list ):

 In [84]: np.fromiter((f(x) for x in range(4)),int) Out[84]: array([0, 1, 4, 9]) In [86]: np.fromiter(map(f, range(4)),int) Out[86]: array([0, 1, 4, 9]) 

Tendrás que hacer tus propios tiempos en un caso realista.

Podría usar la comprensión de lista para disminuir ligeramente el tiempo de ejecución.

 arr = [f(x) for x in range(0, 5)] # range is the interval 

Esto debería funcionar. Sin embargo, sólo disminuirá ligeramente el tiempo de ejecución. No debe preocuparse por el tiempo de ejecución a menos que use números muy grandes con map() .

Utilice operaciones que operan en arreglos completos. Por ejemplo, con una función que solo ajusta la entrada (ligeramente corregida de su ejemplo):

 def f(x): return x**2 

entonces solo harías

 arr = f(X) 

porque NumPy define operadores como ** para operar en arreglos completos a la vez.

Tu función real podría no ser tan sencilla. Usted dice que hay integrales involucrados; para hacer que las operaciones de toda la matriz funcionen con eso, es posible que tenga que pasar argumentos de manera diferente o cambiar lo que está usando para calcular las integrales. En general, sin embargo, las operaciones de todo el conjunto superarán ampliamente cualquier cosa que necesite llamar código de nivel de Python en un bucle.

Podrías probar numpy.vectorize . Es una muy buena manera de aplicar la función a la lista o matriz.

 import numpy as np def foo(x): return x**2 foo = np.vectorize(foo) arr = np.arange(10) In [1]: foo(arr) Out[1]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])