6.11. Redukciók

A redukció egy tömböt egy vagy több tengely mentén összegzéssel, átlagolással, minimum képzésével és így tovább összevon. Minden redukció egyetlen könyvtárhívás a teljes tömbön, ami sokkal gyorsabb, mint a megfelelő Python ciklus. A numpy lefedi a leggyakrabban használtakat:

  • sum() – az összes elem összege

  • mean() – számtani átlag (az összeg osztva az elemek számával)

  • std() – szórás, a ddof= állítja az osztót (N - ddof)

  • min() / max() – a legkisebb és a legnagyobb elem

  • median() – a középső érték, ha az elemek rendezettek (50. percentilis)

  • argmin() / argmax() – a minimális vagy maximális elem indexe

  • all() / any() – igazságérték-redukciók logikai tömbökön

6.11.1. Az axis kulcsszó nélkül

Az axis= nélkül meghívva a redukció a teljes tömböt lefedő skalárt ad vissza:

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. Az axis kulcsszóval

Az axis= egy megnevezett tengelyt von össze, a többit pedig érintetlenül hagyja. Az eredmény egy a bemenetnél eggyel alacsonyabb rangú tömb:

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

Ugyanez az alakszabály érvényes minden redukcióra: az axis=0 az első tengelyt vonja össze, az axis=1 a másodikat, és így tovább. Az átlag / szórás egy sor mentén például így írható: np.mean(m, axis=1) és np.std(m, axis=1). Az eredmény hossza a másik tengely hossza.

A keepdims=True kulcsszó az összevont tengelyt 1 hosszúsággal a helyén tartja ahelyett, hogy elhagyná. A különbség akkor számít, amikor a redukált eredménynek vissza kell broadcastolódnia az eredeti ellen: a keepdims megőrzi a rangot, ami tengelyről tengelyre összehangoltan tartja a broadcasting szabályokat.

Az egyes sorok átlagának az adott sorból való kivonása a kanonikus felhasználás:

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

A keepdims nélkül az np.mean(m, axis=1) egy (3,) alakú 1 dimenziós eredményt ad vissza. A (3, 4) - (3,) broadcastolása a rang elé fűzése után (1, 3) formára igazítja a (3,) alakot, ami nem kompatibilis a (3, 4) alakkal: az utolsó tengelyek eltérnek (4 a 3-mal szemben), és egyik sem 1, így a numpy ValueError hibát vált ki. A keepdims=True az, ami a kivonást érvényben tartja.

6.11.3. Az elrendezés számít

A Alak és lépésközök oldalon tárgyalt sorfolytonos elrendezéssel kombinálva az utolsó tengely menti redukció a legolcsóbb eset. A redukció abban az irányban járja be az adatblokkot, ahogyan az tárolva van, sorról sorra ugrálás nélkül:

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

Amikor az alkalmazás eldöntheti, hogyan rendezzen el egy puffert, tedd a hosszú tengelyt utolsónak, hogy az azon végzett redukciók a gyors irányba fussanak.

6.11.4. Iterálhatók bemenetként

A legtöbb redukció elfogad egy Python iterálhatót (egy list, egy range, egy tuple) az ndarray helyett. A kényelem néhány mikroszekundumba kerül az implicit konverzió miatt – ami egy ciklusban gyorsan összeadódik. Amikor ugyanazokat az adatokat többször redukálod, építsd fel az ndarray objektumot egyszer, és add tovább.