6.9. Funciones universales¶
Una función universal (ufunc) es una función matemática que se aplica a cada elemento de un arreglo en una sola llamada. Los operadores aritméticos de la página anterior son funciones universales con apariencia de operador; esta página es el catálogo de las que tienen nombre y cubren la trigonometría, exp / log, el redondeo y algunas más.
Cada ufunc acepta un escalar, un iterable de Python o un ndarray, y devuelve o bien un único float (cuando la entrada era escalar) o un ndarray de floats:
from ulab import numpy as np
np.exp(2.0) # 7.389...
np.sin(range(4)) # 1-D float ndarray
np.sqrt([1, 4, 9, 16]) # array([1.0, 2.0, 3.0, 4.0])
a = np.arange(9).reshape((3, 3))
np.exp(a) # 3x3 float ndarray
6.9.1. El catálogo¶
numpy expone las funciones matemáticas a las que una aplicación embebida recurre con más frecuencia:
Trigonometría –
sin(),cos(),tan(),asin(),acos(),atan(),arctan2(),sinh(),cosh(),tanh(),asinh(),acosh(),atanh(),sinc().Exponenciales y logaritmos –
exp(),expm1(),log(),log10(),log2(),sqrt().
Cada función procesa todo el arreglo en una sola llamada de biblioteca. La aceleración frente a una comprensión de lista de Python que llama a math.sin() elemento por elemento es de 10 a 30 veces en un búfer típico.
6.9.2. La palabra clave out=¶
Cada llamada a una ufunc normalmente asigna un nuevo arreglo de resultado para contener su salida. En un bucle que se ejecuta muchas veces por segundo, esas asignaciones se acumulan y desperdician RAM. Pasar out= (un arreglo de floats que ya existe, de la misma forma que la entrada) escribe el resultado en ese arreglo en lugar de asignar uno nuevo:
x = np.linspace(0, 2 * np.pi, num=256)
y = np.zeros(256)
while True:
np.sin(x, out=y)
# use y ...
Si out tiene el dtype o la forma incorrectos, la función lanza una excepción. La palabra clave es compatible con todas las ufunc de esta página; es la forma más limpia de mantener libre de asignaciones un bucle de procesamiento de señal en flujo continuo.
6.9.3. Ufuncs de dos argumentos¶
arctan2() es la única ufunc verdadera de dos argumentos de la lista anterior: devuelve el arcotangente de y / x consciente del cuadrante y difunde los dos operandos:
y = np.array([1, 2.2, 33.33, 444.444])
np.arctan2(y, 1.0) # against a scalar
np.arctan2(1.0, y) # the other way
np.arctan2(y, y) # against another array
6.9.4. Componer funciones universales¶
Las funciones universales se componen como cualquier otra expresión de arreglo. Algunos patrones que aparecen en la cámara:
Corrección gamma (en espacio de floats):
gamma = 0.5
out = 255.0 * (frame / 255.0) ** gamma
Un suavizador paso bajo sencillo (un alpha cercano a 1.0 significa actualización lenta):
alpha = 0.95
filtered = alpha * filtered + (1.0 - alpha) * sample
Sigmoide:
sigmoid = 1.0 / (1.0 + np.exp(-x))
Espectro de potencia en dB:
spectrum = 20.0 * np.log10(np.abs(real) + 1e-12)
6.9.5. np.vectorize¶
Una función normal de Python puede promoverse a una con forma de ufunc mediante vectorize(). El invocable resultante acepta escalares, iterables o valores ndarray:
def f(x):
return x * x
vf = np.vectorize(f)
vf(44.0) # array([1936.0])
vf(np.array([1, 2, 3, 4])) # array([1.0, 4.0, 9.0, 16.0])
vf([2, 3, 4]) # array([4.0, 9.0, 16.0])
Por defecto, el dtype del resultado es float. otypes= lo anula:
vf_u8 = np.vectorize(f, otypes=np.uint8)
vf_u8([1, 2, 3, 4])
# array([1, 4, 9, 16], dtype=uint8)
La función de Python debe tomar un único argumento y devolver un único número.
vectorize() es en su mayor parte sintáctico: la función de Python envuelta sigue teniendo que ejecutarse una vez por elemento, así que la mayor parte del coste del intérprete por elemento que una ufunc verdadera evita vuelve a estar presente. Espera una aceleración modesta del 30 %-50 % frente a una comprensión de lista, no las 30 veces de una función universal verdadera. Es la herramienta adecuada cuando una función tiene que funcionar con escalares, listas y arreglos bajo el mismo nombre, no cuando el objetivo es la velocidad pura.
Para ver las firmas de llamada completas de todas las funciones universales listadas arriba, consulta numpy — operaciones con arreglos compatibles con numpy.