6.11. Pelkistykset

Pelkistys tiivistää taulukon yhden tai useamman akselin suuntaisesti summaamalla, laskemalla keskiarvon, ottamalla minimin ja niin edelleen. Jokainen pelkistys on yksittäinen kirjastokutsu koko taulukolle, paljon nopeampi kuin vastaava Python-silmukka. numpy kattaa jokapäiväiset pelkistykset:

  • sum() – kaikkien alkioiden summa

  • mean() – aritmeettinen keskiarvo (summa jaettuna alkioiden lukumäärällä)

  • std() – keskihajonta, ddof= säätää jakajaa (N - ddof)

  • min() / max() – pienin ja suurin alkio

  • median() – keskimmäinen arvo, kun alkiot on lajiteltu (50. persentiili)

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

  • all() / any() – totuusarvopelkistykset Boolen taulukoille

6.11.1. Ilman axis-avainsanaa

Ilman axis=-avainsanaa kutsuttuna pelkistys palauttaa skalaarin, joka kattaa koko taulukon:

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. axis-avainsanan kanssa

axis= kutistaa yhden nimetyn akselin ja jättää muut ennalleen. Tulos on taulukko, jonka kertaluku on yhtä pienempi kuin syötteen:

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

Sama muotosääntö pätee jokaiseen pelkistykseen: axis=0 kutistaa ensimmäisen akselin, axis=1 kutistaa toisen ja niin edelleen. Esimerkiksi rivin suuntainen keskiarvo / keskihajonta kirjoitetaan np.mean(m, axis=1) ja np.std(m, axis=1). Tuloksen pituus vastaa toisen akselin pituutta.

keepdims=True-avainsana säilyttää kutistetun akselin paikallaan pituudella 1 sen poistamisen sijaan. Erolla on merkitystä, kun pelkistetyn tuloksen täytyy lähettää (broadcast) takaisin alkuperäistä vastaan: keepdims säilyttää kertaluvun, mikä pitää lähetyssäännöt linjassa akseli akselilta.

Kunkin rivin keskiarvon vähentäminen kyseiseltä riviltä on tyypillinen käyttötapa:

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

Ilman keepdims-avainsanaa np.mean(m, axis=1) palauttaa 1-ulotteisen tuloksen, jonka muoto on (3,). Lähetys (3, 4) - (3,) asettaa muodon (3,) muotoon (1, 3) kertaluvun etuliitteen lisäämisen jälkeen, mikä on yhteensopimaton muodon (3, 4) kanssa: viimeiset akselit ovat ristiriidassa (4 vastaan 3) eikä kumpikaan ole 1, joten numpy nostaa poikkeuksen ValueError. keepdims=True on se, mikä pitää vähennyksen kelvollisena.

6.11.3. Sijoittelulla on merkitystä

Yhdessä rivijärjestyksen kanssa, joka käsiteltiin sivulla Muoto ja askelvälit, viimeisen akselin suuntainen pelkistys on edullisin tapaus. Pelkistys kulkee datalohkon läpi siihen suuntaan, johon se on tallennettu, ilman hyppyjä rivistä toiseen:

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

Kun sovellus voi vaikuttaa siihen, miten puskuri sijoitetaan muistiin, laita pitkä akseli viimeiseksi, jotta sen suuntaiset pelkistykset toimivat nopeaan suuntaan.

6.11.4. Iteroitavat syötteenä

Useimmat pelkistykset hyväksyvät Python-iteroitavan (list, range, monikko) ndarray-olion sijaan. Tämä mukavuus maksaa muutaman mikrosekunnin implisiittisestä muunnoksesta – mikä kertyy nopeasti silmukassa. Kun samaa dataa pelkistetään useita kertoja, rakenna ndarray kerran ja välitä se eteenpäin.