Esta es una dificultad conceptual común cuando se aprende a usar NumPy de manera efectiva. Normalmente, el procesamiento de datos en Python se expresa mejor en términos de iteradores , para mantener el uso de memoria bajo, para maximizar las oportunidades de paralelismo con el sistema de E / S y para reutilizar y combinar partes de algoritmos .
Pero NumPy hace que todo sea al revés: el mejor enfoque es expresar el algoritmo como una secuencia de operaciones de todo el conjunto , para minimizar la cantidad de tiempo empleado en el lento intérprete de Python y maximizar el cantidad de tiempo empleado en rutinas NumPy compiladas rápidamente.
Aquí está el enfoque general que tomo:
-
Mantenga la versión original de la función (que está seguro de que es correcta) para que pueda probarla en comparación con sus versiones mejoradas, tanto en cuanto a corrección como en velocidad.
-
Trabaja desde adentro hacia afuera: es decir, comienza con el bucle más interno y ve si se puede vectorizar; luego, cuando haya hecho eso, salga de un nivel y continúe.
-
Pase mucho tiempo leyendo la documentación de NumPy . Hay muchas funciones y operaciones allí y no siempre tienen nombres brillantes, por lo que vale la pena conocerlas. En particular, si se encuentra pensando, "si solo hubiera una función que hiciera tal o cual cosa", entonces vale la pena dedicar diez minutos a buscarla. Por lo general, está en algún lugar.
No hay sustituto para la práctica, así que voy a darte algunos problemas de ejemplo. El objetivo de cada problema es volver a escribir la función para que esté completamente vectorizada : es decir, para que consista en una secuencia de operaciones NumPy en arrays completos, sin bucles nativos de Python (sin for
o while
de declaraciones, sin iteradores ni comprensiones).
Problema 1
def sumproducts(x, y):
"""Return the sum of x[i] * y[j] for all pairs of indices i, j.
>>> sumproducts(np.arange(3000), np.arange(3000))
20236502250000
"""
result = 0
for i in range(len(x)):
for j in range(len(y)):
result += x[i] * y[j]
return result
Problema 2
def countlower(x, y):
"""Return the number of pairs i, j such that x[i] < y[j].
>>> countlower(np.arange(0, 200, 2), np.arange(40, 140))
4500
"""
result = 0
for i in range(len(x)):
for j in range(len(y)):
if x[i] < y[j]:
result += 1
return result
Problema 3
def cleanup(x, missing=-1, value=0):
"""Return an array that's the same as x, except that where x ==
missing, it has value instead.
>>> cleanup(np.arange(-3, 3), value=10)
... # doctest: +NORMALIZE_WHITESPACE
array([-3, -2, 10, 0, 1, 2])
"""
result = []
for i in range(len(x)):
if x[i] == missing:
result.append(value)
else:
result.append(x[i])
return np.array(result)
Spoilers abajo. ¡Obtendrá los mejores resultados si lo hace antes de ver mis soluciones!
Respuesta 1
np.sum (x) * np.sum (y)
Respuesta 2
np.sum (np.searchsorted (np.sort (x), y))
Respuesta 3
np.where (x == falta, valor, x)