6.12. Kiválasztás és átrendezés

A redukciók egy tömböt skalárrá vagy alacsonyabb rangú eredménnyé vontak össze. A kiválasztás azokat a műveleteket fedi le, amelyek megválasztják, hogy mely elemek maradnak meg és hol végzik: feltételes választás, vágás, rendezés, indexek keresése, tengely menti átrendezés.

6.12.1. Feltételes választás

A where() olyan tömböt ad vissza, amely ott vesz elemeket az x tömbből, ahol a feltétel igaz, egyébként pedig az y tömbből. A három operandus együtt broadcastolódik:

a = np.array([1, 2, 3, 4, 5], dtype=np.float)
np.where(a < 3, a, 0.0)
# array([1.0, 2.0, 0.0, 0.0, 0.0])

Ez a megfelelő eszköz egy „elemenkénti if/else” megvalósításához Python ciklus írása nélkül.

A clip() a maximum(lo, minimum(a, hi)) rövidített alakja – az értékeket egy tartományra telíti:

np.clip(a, 2.0, 4.0)
# array([2.0, 2.0, 3.0, 4.0, 4.0])

A maximum() és a minimum() két operandust vesz, és elemenként a nagyobbat / kisebbet adja vissza:

np.maximum(a, 3.0)
np.minimum(a, np.array([5, 4, 3, 2, 1]))

6.12.2. Indexek keresése

A nonzero() minden nem nulla elem koordinátáit visszaadja, dimenziónként egy-egy indextömbre bontva. Egy 2 dimenziós bemenetnél az eredmény két tömb tuple-je: az első a sorindexeket, a második az oszlopindexeket tartalmazza. Oszloponként párosítva őket megkapjuk minden nem nulla pozíció (row, col) koordinátáját:

m = np.array([[0, 2, 0],
              [3, 0, 0]], dtype=np.float)
np.nonzero(m)
# (array([0, 1], dtype=uint16), array([1, 0], dtype=uint16))

Az m nem nulla bejegyzései m[0, 1] = 2 és m[1, 0] = 3. Az első visszaadott tömb [0, 1] a sorindexeiket adja meg; a második [1, 0] az oszlopindexeiket. A két tömböt egymás mellett olvasva visszakapjuk a (0, 1) és (1, 0) pozíciókat.

Két redukció szintén indexeket állít elő:

  • argmin() / argmax() – a legkisebb / legnagyobb elem indexe.

  • argsort() – egy egész tömb, amely a bemenetet rendezné az adott tengely mentén (alapértelmezésben az utolsó mentén):

    a = np.array([40, 10, 30, 20], dtype=np.uint8)
    idx = np.argsort(a)             # array([1, 3, 2, 0], dtype=uint16)
    a[idx]                          # array([10, 20, 30, 40])
    

    Az argsort mindig uint16 típust ad vissza; a rendezett tömbnek ezért a rendezett tengelyen legfeljebb 65 535 eleme lehet.

A bincount() megszámolja minden nem negatív egész előfordulását egy 1 dimenziós uint8 / uint16 bemenetben:

histogram = np.bincount(np.array([0, 1, 1, 2, 2, 2], dtype=np.uint8))
# array([1, 2, 3], dtype=uint16)

Hasznos kis egész értékű képpontértékek hisztogramjainak felépítéséhez Python ciklus írása nélkül.

6.12.3. Rendezés és átrendezés

A sort() a tömb rendezett másolatát adja vissza az adott tengely mentén (alapértelmezésben az utolsó mentén). Használd a sort() metódust közvetlenül a tömbön a helyben végzett változathoz:

np.sort(np.array([3, 1, 2], dtype=np.float))
# array([1.0, 2.0, 3.0])

A flip() megfordítja a sorrendet az adott tengely mentén (minden tengely mentén, ha nincs megadva axis):

np.flip(np.array([1, 2, 3, 4]))
# array([4, 3, 2, 1])

A roll() ciklikusan eltolja az elemeket a megadott számmal. Hasznos gyűrűpuffer-szerű léptetőregiszter megvalósításához:

np.roll(np.array([1, 2, 3, 4]), 1)
# array([4, 1, 2, 3])

A take() a fancy indexelés explicit alakja – tetszőleges indexeknél választ elemeket:

a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.take(a, [0, 2, 4])
# array([10, 30, 50], dtype=uint8)

6.12.4. Szűrés és szerkezeti módosítások

A compress() a logikai indexelés explicit alakja – a logikai feltétel által kiválasztott szeleteit adja vissza az a tömbnek:

a = np.array([10, 20, 30, 40], dtype=np.uint8)
np.compress(a > 15, a)
# array([20, 30, 40], dtype=uint8)

A delete() egy másolatot ad vissza, amelyből a megadott indexeknél lévő bejegyzések el vannak távolítva:

a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.delete(a, [1, 3])
# array([10, 30, 50], dtype=uint8)

A diff() a tömb n-edik diszkrét előremutató differenciáját adja vissza egy tengely mentén. A szomszédos minták közötti elsőrendű változások kiszámítására használatos:

samples = np.array([1, 3, 6, 10, 15], dtype=np.float)
np.diff(samples)
# array([2.0, 3.0, 4.0, 5.0])

6.12.5. Mibe kerül az egyes műveletek

Ezen az oldalon szinte minden függvény frissen lefoglalt tömböt ad vissza. Két kivétel:

  • A sort() helyben rendez; a szabad sort() függvény rendezett másolatot ad vissza.

  • A take() elfogad egy out= kulcsszót, hogy egy már létező pufferbe írjon.

Egy másodpercenként sokszor futó ciklusban részesítsd előnyben a helyben működő sort() metódust, és máshol mindenütt használj újra előre lefoglalt puffereket. Maguk a logikai maszkok minden alkalommal lefoglalódnak, amikor az összehasonlítás lefut – építs fel egy maszkot egyszer, és használd újra a műveleteken keresztül, ahelyett hogy minden iterációban újraépítenéd.