6.12. Valinta ja uudelleenjärjestely

Pelkistykset tiivistivät taulukon skalaariksi tai pienemmän kertaluvun tulokseksi. Valinta kattaa operaatiot, jotka poimivat mitkä alkiot säilyvät ja mihin ne päätyvät: ehdollinen valinta, leikkaus, lajittelu, indeksien etsiminen, uudelleenjärjestely akselin suunnassa.

6.12.1. Ehdollinen valinta

where() palauttaa taulukon, joka ottaa alkiot taulukosta x siellä missä ehto on tosi ja muuten taulukosta y. Kolme operandia lähetetään (broadcast) yhdessä:

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])

Tämä on oikea työkalu ”jos/muuten alkiokohtaisesti” -tarpeeseen ilman Python-silmukan kirjoittamista.

clip() on lyhennelmä ilmaisulle maximum(lo, minimum(a, hi)) – kyllästä arvot tietylle alueelle:

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

maximum() ja minimum() ottavat kaksi operandia ja palauttavat alkioittain suuremman / pienemmän:

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

6.12.2. Indeksien etsiminen

nonzero() palauttaa jokaisen nollasta poikkeavan alkion koordinaatit, jaettuna yhteen indeksitaulukkoon ulottuvuutta kohden. 2-ulotteiselle syötteelle tulos on kahden taulukon monikko: ensimmäinen sisältää rivi-indeksit, toinen sarakeindeksit. Sarakkeittain pareittain yhdistettynä ne antavat kunkin nollasta poikkeavan sijainnin (row, col)

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))

Taulukon m nollasta poikkeavat alkiot ovat m[0, 1] = 2 ja m[1, 0] = 3. Ensimmäinen palautettu taulukko [0, 1] antaa niiden rivi-indeksit; toinen [1, 0] antaa niiden sarakeindeksit. Kun nämä kaksi taulukkoa luetaan rinnakkain, saadaan takaisin sijainnit (0, 1) ja (1, 0).

Myös kaksi pelkistystä tuottaa indeksejä:

  • argmin() / argmax() – pienimmän / suurimman alkion indeksi.

  • argsort() – kokonaislukutaulukko, joka lajittelisi syötteen annetun akselin suunnassa (oletuksena viimeinen):

    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])
    

    argsort palauttaa aina tyyppiä uint16; lajiteltavassa taulukossa saa siksi olla enintään 65 535 alkiota lajiteltavalla akselilla.

bincount() laskee kunkin ei-negatiivisen kokonaisluvun esiintymät 1-ulotteisessa uint8 / uint16 -syötteessä:

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

Hyödyllinen pienten kokonaislukupikselien arvojen histogrammien rakentamiseen ilman Python-silmukkaa.

6.12.3. Lajittelu ja uudelleenjärjestely

sort() palauttaa lajitellun kopion taulukosta annetun akselin suunnassa (oletuksena viimeinen). Käytä sort() suoraan taulukolle paikallaan tapahtuvaan lajitteluun:

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

flip() kääntää järjestyksen annetun akselin suunnassa (jokaisen akselin, kun axis ei ole annettu):

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

roll() siirtää alkioita syklisesti annetulla määrällä. Hyödyllinen rengaspuskurityylisen siirtorekisterin toteuttamiseen:

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

take() on hienostuneen indeksoinnin eksplisiittinen muoto – poimi alkiot mielivaltaisista indekseistä:

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. Suodatus ja rakenteelliset muokkaukset

compress() on Boolen indeksoinnin eksplisiittinen muoto – palauttaa taulukon a viipaleet, jotka Boolen ehto valitsee:

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

delete() palauttaa kopion, josta on poistettu annetuissa indekseissä olevat alkiot:

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

diff() palauttaa taulukon n:nnen diskreetin eteenpäin lasketun erotuksen akselin suunnassa. Käytetään ensimmäisen kertaluvun muutosten laskemiseen peräkkäisten näytteiden välillä:

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. Mitä kukin operaatio maksaa

Lähes jokainen tämän sivun funktio palauttaa juuri varatun taulukon. Kaksi poikkeusta:

  • sort() lajittelee paikallaan; vapaa funktio sort() palauttaa lajitellun kopion.

  • take() hyväksyy out=-avainsanan, joka kirjoittaa jo olemassa olevaan puskuriin.

Silmukassa, joka suoritetaan monta kertaa sekunnissa, suosi paikallaan toimivaa sort() -funktiota ja käytä esivarattuja puskureita uudelleen kaikkialla muualla. Boolen maskit itse varataan joka kerta, kun vertailu suoritetaan – rakenna maski kerran ja käytä sitä uudelleen operaatioiden välillä sen sijaan, että rakentaisit sen uudelleen jokaisessa iteraatiossa.