6.11. Reducties¶
Een reductie vouwt een array samen langs een of meer assen door op te tellen, te middelen, een minimum te nemen, enzovoort. Elke reductie is een enkele bibliotheekaanroep over de hele array, veel sneller dan de equivalente Python-lus. numpy dekt de alledaagse gevallen:
sum()– totaal van elk elementmean()– rekenkundig gemiddelde (som gedeeld door het aantal elementen)std()– standaarddeviatie,ddof=past de deler aan (N - ddof)median()– middelste waarde wanneer de elementen gesorteerd zijn (50e percentiel)argmin()/argmax()– de index van het minimum- of maximumelementall()/any()– waarheidswaarde-reducties op booleaanse arrays
6.11.1. Zonder het axis-trefwoord¶
Aangeroepen zonder axis= levert een reductie een scalair op dat de hele array beslaat:
a = np.array([1, 2, 3, 4], dtype=np.float)
np.sum(a) # 10.0
np.mean(a) # 2.5
np.std(a) # 1.118...
np.median(a) # 2.5
b = np.array([40, 10, 30, 20], dtype=np.float)
np.max(b) # 40.0
np.argmax(b) # 0 (index of the maximum)
6.11.2. Met het axis-trefwoord¶
axis= trekt een genoemde as samen en laat de overige intact. Het resultaat is een array met een rang lager dan de invoer:
m = np.arange(12, dtype=np.float).reshape((3, 4))
np.sum(m) # 66.0 - scalar
np.sum(m, axis=0) # length-4 - column sums
np.sum(m, axis=1) # length-3 - row sums
Dezelfde vormregel geldt voor elke reductie: axis=0 vouwt de eerste as samen, axis=1 vouwt de tweede samen, enzovoort. Gemiddelde / standaarddeviatie langs een rij worden bijvoorbeeld geschreven als np.mean(m, axis=1) en np.std(m, axis=1). Het resultaat heeft de lengte van de andere as.
Het trefwoord keepdims=True houdt de samengetrokken as op zijn plaats met lengte 1 in plaats van die weg te laten. Het onderscheid is van belang wanneer het gereduceerde resultaat terug moet broadcasten tegen de oorspronkelijke array: keepdims behoudt de rang, waardoor de broadcastingregels as-voor-as op elkaar afgestemd blijven.
Het aftrekken van het gemiddelde van elke rij van die rij is het klassieke gebruik:
m = np.arange(12, dtype=np.float).reshape((3, 4))
row_means = np.mean(m, axis=1, keepdims=True)
# row_means has shape (3, 1)
centred = m - row_means
# (3, 4) - (3, 1) -> (3, 4), each row centred on its own mean
Zonder keepdims levert np.mean(m, axis=1) een 1-D-resultaat op met vorm (3,). Bij het broadcasten van (3, 4) - (3,) wordt (3,) na het toevoegen van de rang vooraan uitgelijnd als (1, 3), wat onverenigbaar is met (3, 4): de laatste assen komen niet overeen (4 tegen 3) en geen van beide is 1, dus numpy werpt ValueError. keepdims=True is wat de aftrekking geldig houdt.
6.11.3. Indeling is van belang¶
Gecombineerd met de rij-georiënteerde indeling die op Vorm en strides wordt behandeld, is reduceren langs de laatste as het goedkoopste geval. De reductie doorloopt het datablok in de richting waarin het is opgeslagen, zonder sprongen van rij naar rij:
m = np.arange(2000, dtype=np.float).reshape((2, 1000))
np.sum(m, axis=1) # cheap - long axis is the inner one
np.sum(m, axis=0) # has to jump rows on every step
Wanneer de applicatie kan kiezen hoe een buffer wordt ingedeeld, zet dan de lange as als laatste, zodat reducties langs die as in de snelle richting verlopen.
6.11.4. Iterables als invoer¶
De meeste reducties accepteren een Python-iterable (een list, een range, een tuple) in plaats van een ndarray. Dat gemak kost een paar microseconden voor de impliciete conversie – wat in een lus snel oploopt. Wanneer dezelfde data meerdere keren wordt gereduceerd, bouw de ndarray dan eenmalig op en geef die door.