6.11. Reduktioner¶
En reduktion kollapsar en array längs en eller flera axlar genom att summera, beräkna medelvärde, ta ett minimum och så vidare. Varje reduktion är ett enda biblioteksanrop mot hela arrayen, vilket är mycket snabbare än motsvarande Python-loop. numpy täcker de vanligaste:
sum()– summan av alla elementmean()– aritmetiskt medelvärde (summan delad med antalet element)std()– standardavvikelse,ddof=justerar nämnaren (N - ddof)median()– mittvärdet när elementen är sorterade (50:e percentilen)argmin()/argmax()– indexet för det minsta eller största elementetall()/any()– sanningsvärdesreduktioner på booleska arrayer
6.11.1. Utan nyckelordet axis¶
Anropad utan axis= returnerar en reduktion en skalär som täcker hela arrayen:
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. Med nyckelordet axis¶
axis= kontraherar en namngiven axel och lämnar de övriga orörda. Resultatet är en array av en rang lägre än indata:
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
Samma formregel gäller för alla reduktioner: axis=0 kollapsar den första axeln, axis=1 kollapsar den andra, och så vidare. Medelvärde / standardavvikelse längs en rad skrivs till exempel np.mean(m, axis=1) och np.std(m, axis=1). Resultatet har längden av den andra axeln.
Nyckelordet keepdims=True behåller den kontraherade axeln på plats med längden 1 istället för att ta bort den. Skillnaden spelar roll när det reducerade resultatet behöver broadcastas tillbaka mot originalet: keepdims bevarar rangen, vilket håller broadcasting-reglerna i linje axel för axel.
Att subtrahera varje rads medelvärde från den raden är den kanoniska användningen:
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
Utan keepdims returnerar np.mean(m, axis=1) ett 1-D-resultat med formen (3,). Broadcasting av (3, 4) - (3,) placerar (3,) som (1, 3) efter att rangen lagts till framtill, vilket är inkompatibelt med (3, 4): de sista axlarna stämmer inte överens (4 mot 3) och ingen är 1, så numpy utlöser ValueError. keepdims=True är det som gör subtraktionen giltig.
6.11.3. Layouten spelar roll¶
Kombinerat med den radvisa layouten som beskrivs i Form och strides är reduktion längs den sista axeln det billigaste fallet. Reduktionen går igenom datablocket i den riktning det är lagrat, utan hopp från rad till rad:
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
När applikationen kan välja hur en buffert ska läggas ut, placera den långa axeln sist så att reduktioner längs den körs i den snabba riktningen.
6.11.4. Itererbara objekt som indata¶
De flesta reduktioner accepterar ett itererbart Python-objekt (en list, ett range, en tupel) i stället för en ndarray. Bekvämligheten kostar några mikrosekunder för den implicita konverteringen – vilket snabbt adderas i en loop. När samma data reduceras flera gånger, bygg ndarray en gång och skicka runt den.