6.9. Funkcje uniwersalne¶
Funkcja uniwersalna (ufunc) to funkcja matematyczna, która jednym wywołaniem działa na każdym elemencie tablicy. Operatory arytmetyczne z poprzedniej strony to funkcje uniwersalne ubrane w składnię operatorów; ta strona jest katalogiem tych nazwanych, obejmujących trygonometrię, exp / log, zaokrąglanie i kilka innych.
Każda ufunc przyjmuje skalar, iterowalny obiekt Pythona lub ndarray i zwraca albo pojedynczą liczbę zmiennoprzecinkową (gdy wejście było skalarem), albo zmiennoprzecinkową ndarray
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. Katalog¶
numpy udostępnia funkcje matematyczne, po które aplikacja wbudowana sięga najczęściej:
Trygonometria –
sin(),cos(),tan(),asin(),acos(),atan(),arctan2(),sinh(),cosh(),tanh(),asinh(),acosh(),atanh(),sinc().Funkcje wykładnicze i logarytmy –
exp(),expm1(),log(),log10(),log2(),sqrt().
Każda funkcja przetwarza całą tablicę w jednym wywołaniu biblioteki. Przyspieszenie względem listy składanej w Pythonie wywołującej math.sin() element po elemencie wynosi 10-30x na typowym buforze.
6.9.2. Słowo kluczowe out=¶
Każde wywołanie ufunc normalnie alokuje świeżą tablicę wynikową, aby pomieścić jej wyjście. W pętli wykonywanej wiele razy na sekundę te alokacje narastają i marnują pamięć RAM. Przekazanie out= – już istniejącej tablicy zmiennoprzecinkowej o tym samym kształcie co dane wejściowe – zapisuje wynik do tej tablicy zamiast alokować nową:
x = np.linspace(0, 2 * np.pi, num=256)
y = np.zeros(256)
while True:
np.sin(x, out=y)
# use y ...
Jeśli out ma niewłaściwy dtype lub kształt, funkcja zgłasza wyjątek. To słowo kluczowe jest obsługiwane przez każdą ufunc na tej stronie; jest to najczystszy sposób, by strumieniowa pętla przetwarzania sygnału pozostała wolna od alokacji.
6.9.3. Funkcje uniwersalne dwuargumentowe¶
arctan2() to jedyna prawdziwa dwuargumentowa ufunc na powyższej liście – zwraca arcus tangens y / x ze świadomością ćwiartki i rozpropagowuje oba operandy:
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. Składanie funkcji uniwersalnych¶
Funkcje uniwersalne składają się jak każde inne wyrażenie tablicowe. Kilka wzorców, które pojawiają się na kamerze:
Korekcja gamma (w przestrzeni zmiennoprzecinkowej)
gamma = 0.5
out = 255.0 * (frame / 255.0) ** gamma
Prosty wygładzacz dolnoprzepustowy (alpha bliskie 1.0 oznacza wolną aktualizację):
alpha = 0.95
filtered = alpha * filtered + (1.0 - alpha) * sample
Sigmoida
sigmoid = 1.0 / (1.0 + np.exp(-x))
Widmo mocy w dB
spectrum = 20.0 * np.log10(np.abs(real) + 1e-12)
6.9.5. np.vectorize¶
Zwykła funkcja Pythona może zostać przekształcona w funkcję o kształcie ufunc za pomocą vectorize(). Powstały obiekt wywoływalny przyjmuje skalary, obiekty iterowalne lub wartości 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])
Domyślnie typem wynikowym jest float. otypes= go nadpisuje:
vf_u8 = np.vectorize(f, otypes=np.uint8)
vf_u8([1, 2, 3, 4])
# array([1, 4, 9, 16], dtype=uint8)
Funkcja Pythona musi przyjmować pojedynczy argument i zwracać pojedynczą liczbę.
vectorize() jest głównie składniowa – opakowana funkcja Pythona wciąż musi być uruchamiana raz na element, więc większość kosztu interpretera na element, którego prawdziwa ufunc unika, powraca. Spodziewaj się umiarkowanego przyspieszenia o 30%-50% względem listy składanej, a nie 30x prawdziwej funkcji uniwersalnej. Właściwe narzędzie, gdy jedna funkcja musi działać na skalarach, listach i tablicach pod tą samą nazwą – a nie wtedy, gdy celem jest surowa szybkość.
Pełne sygnatury wywołań każdej z wymienionych powyżej funkcji uniwersalnych znajdziesz w numpy — operacje na tablicach zgodne z numpy.