6.9. Universele functies¶
Een universele functie (ufunc) is een wiskundige functie die in één aanroep op elk element van een array wordt toegepast. De rekenkundige operatoren op de vorige pagina zijn universele functies in operatorsyntaxis; deze pagina is de catalogus van de benoemde varianten die trigonometrie, exp / log, afronding en enkele andere dekken.
Elke ufunc accepteert een scalair, een Python-iterable of een ndarray, en geeft ofwel een enkele float terug (wanneer de invoer een scalair was) ofwel een float-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. De catalogus¶
numpy stelt de wiskundige functies beschikbaar die een ingebedde applicatie het vaakst nodig heeft:
Trigonometrie –
sin(),cos(),tan(),asin(),acos(),atan(),arctan2(),sinh(),cosh(),tanh(),asinh(),acosh(),atanh(),sinc().Exponentiëlen en logaritmen –
exp(),expm1(),log(),log10(),log2(),sqrt().
Elke functie verwerkt de hele array in één bibliotheekaanroep. De versnelling ten opzichte van een Python-list-comprehension die math.sin() element voor element aanroept, is 10-30x op een typische buffer.
6.9.2. Het out=-trefwoord¶
Elke ufunc-aanroep wijst normaal gesproken een verse resultaatarray toe om de uitvoer in op te slaan. In een lus die vele keren per seconde draait, lopen die toewijzingen op en verspillen ze RAM. Door out= mee te geven – een al bestaande float-array van dezelfde vorm als de invoer – wordt het resultaat in die array geschreven in plaats van een nieuwe toe te wijzen:
x = np.linspace(0, 2 * np.pi, num=256)
y = np.zeros(256)
while True:
np.sin(x, out=y)
# use y ...
Als out de verkeerde dtype of vorm heeft, werpt de functie een uitzondering. Het trefwoord wordt door elke ufunc op deze pagina ondersteund; het is de schoonste manier om een streaming signaalverwerkingslus toewijzingsvrij te houden.
6.9.3. Ufuncs met twee argumenten¶
arctan2() is de enige echte ufunc met twee argumenten in de bovenstaande lijst – die geeft de kwadrantbewuste arctangens van y / x terug en broadcast de twee operanden:
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. Universele functies samenstellen¶
Universele functies stellen zich samen als elke andere array-expressie. Een paar patronen die op de camera voorkomen:
Gammacorrectie (in float-ruimte)
gamma = 0.5
out = 255.0 * (frame / 255.0) ** gamma
Een eenvoudige laagdoorlaatfilter (alpha dicht bij 1.0 betekent trage update):
alpha = 0.95
filtered = alpha * filtered + (1.0 - alpha) * sample
Sigmoïde
sigmoid = 1.0 / (1.0 + np.exp(-x))
Vermogensspectrum in dB
spectrum = 20.0 * np.log10(np.abs(real) + 1e-12)
6.9.5. np.vectorize¶
Een gewone Python-functie kan worden gepromoveerd tot een ufunc-vormige door vectorize(). De resulterende callable accepteert scalairen, iterables of ndarray-waarden:
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])
Standaard is de resultaat-dtype float. otypes= overschrijft die:
vf_u8 = np.vectorize(f, otypes=np.uint8)
vf_u8([1, 2, 3, 4])
# array([1, 4, 9, 16], dtype=uint8)
De Python-functie moet één argument aannemen en één getal teruggeven.
vectorize() is grotendeels syntactisch – de omhulde Python-functie moet nog steeds eenmaal per element draaien, dus het grootste deel van de per-element interpreterkosten die een echte ufunc vermijdt, is terug. Verwacht een bescheiden versnelling van 30%-50% ten opzichte van een list-comprehension, niet de 30x van een echte universele functie. Het juiste gereedschap wanneer één functie onder dezelfde naam op scalairen, lijsten én arrays moet werken – niet wanneer pure snelheid het doel is.
Voor de volledige aanroepsignaturen van elke hierboven genoemde universele functie, zie numpy — numpy-compatibele arraybewerkingen.