6.11. Reduceri¶
O reducere comprimă un tablou de-a lungul uneia sau mai multor axe prin însumare, mediere, calculul minimului și așa mai departe. Fiecare reducere este un singur apel de bibliotecă asupra întregului tablou, mult mai rapid decât bucla Python echivalentă. numpy acoperă pe cele uzuale:
sum()– totalul fiecărui elementmean()– media aritmetică (suma împărțită la numărul de elemente)std()– abaterea standard,ddof=ajustează divizorul (N - ddof)median()– valoarea de mijloc atunci când elementele sunt sortate (percentila 50)all()/any()– reduceri de valoare de adevăr pe tablouri booleene
6.11.1. Fără cuvântul-cheie axis¶
Apelată fără axis=, o reducere returnează un scalar care acoperă întregul tablou:
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. Cu cuvântul-cheie axis¶
axis= contractă o singură axă numită și le lasă pe celelalte intacte. Rezultatul este un tablou cu un rang mai mic decât intrarea:
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
Aceeași regulă a formei se aplică fiecărei reduceri: axis=0 comprimă prima axă, axis=1 comprimă a doua și așa mai departe. Media / abaterea standard de-a lungul unui rând, de exemplu, se scriu np.mean(m, axis=1) și np.std(m, axis=1). Rezultatul are lungimea celeilalte axe.
Cuvântul-cheie keepdims=True păstrează axa contractată pe loc cu lungimea 1 în loc să o elimine. Distincția contează atunci când rezultatul redus trebuie să se difuzeze (broadcast) înapoi față de originalul: keepdims păstrează rangul, ceea ce menține regulile de difuzare aliniate axă cu axă.
Scăderea mediei fiecărui rând din acel rând este utilizarea canonică:
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
Fără keepdims, np.mean(m, axis=1) returnează un rezultat 1-D de forma (3,). Difuzarea (3, 4) - (3,) aliniază (3,) ca (1, 3) după adăugarea rangului în față, ceea ce este incompatibil cu (3, 4): ultimele axe nu se potrivesc (4 față de 3) și niciuna nu este 1, deci numpy ridică ValueError. keepdims=True este ceea ce menține scăderea validă.
6.11.3. Aranjarea contează¶
Combinată cu aranjarea pe rânduri (row-major) tratată în Formă și pași (strides), reducerea de-a lungul ultimei axe este cazul cel mai ieftin. Reducerea parcurge blocul de date în direcția în care este stocat, fără salturi de la rând la rând:
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
Atunci când aplicația are libertatea de a alege cum să dispună un tampon (buffer), pune axa lungă pe ultima poziție, astfel încât reducerile de-a lungul ei să ruleze în direcția rapidă.
6.11.4. Iterabile ca intrare¶
Majoritatea reducerilor acceptă un iterabil Python (o list, un range, un tuplu) în locul unui ndarray. Comoditatea costă câteva microsecunde pentru conversia implicită – ceea ce se adună rapid într-o buclă. Atunci când aceleași date sunt reduse de mai multe ori, construiește ndarray o singură dată și transmite-l mai departe.