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.