6.12. Selectare și rearanjare

Reducerile comprimau un tablou până la un scalar sau un rezultat de rang mai mic. Selectarea acoperă operațiile care aleg care elemente supraviețuiesc și unde ajung: alegere condiționată, limitare, sortare, căutarea indicilor, reordonarea de-a lungul unei axe.

6.12.1. Alegere condiționată

where() returnează un tablou care preia elemente din x acolo unde condiția este adevărată și din y în caz contrar. Cei trei operanzi se difuzează împreună:

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

Acesta este instrumentul potrivit pentru un „if/else per element” fără a scrie o buclă Python.

clip() este o prescurtare pentru maximum(lo, minimum(a, hi)) – saturează valorile la un interval:

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

maximum() și minimum() iau doi operanzi și returnează, element cu element, valoarea mai mare / mai mică:

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

6.12.2. Găsirea indicilor

nonzero() returnează coordonatele fiecărui element diferit de zero, împărțite într-un tablou de indici per dimensiune. Pentru o intrare 2-D, rezultatul este un tuplu de două tablouri: primul conține indicii de rând, al doilea conține indicii de coloană. Împerecherea lor pe coloane dă (row, col) al fiecărei poziții diferite de zero:

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

Intrările diferite de zero din m sunt m[0, 1] = 2 și m[1, 0] = 3. Primul tablou returnat [0, 1] dă indicii lor de rând; al doilea [1, 0] dă indicii lor de coloană. Citind cele două tablouri unul lângă altul se recuperează pozițiile (0, 1) și (1, 0).

Două reduceri produc, de asemenea, indici:

  • argmin() / argmax() – indicele celui mai mic / mai mare element.

  • argsort() – un tablou de întregi care ar sorta intrarea de-a lungul axei date (implicit ultima):

    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 returnează întotdeauna uint16; prin urmare, tabloul sortat nu trebuie să aibă mai mult de 65.535 de elemente pe axa sortată.

bincount() numără aparițiile fiecărui întreg nenegativ într-o intrare 1-D uint8 / uint16

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

Util pentru construirea histogramelor de valori de pixeli de tip întreg mic fără a scrie o buclă Python.

6.12.3. Sortare și reordonare

sort() returnează o copie sortată a tabloului de-a lungul axei date (implicit ultima). Folosește sort() direct pe tablou pentru o versiune pe loc:

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

flip() inversează ordinea de-a lungul axei date (fiecare axă atunci când nu se transmite niciun axis):

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

roll() deplasează ciclic elementele cu numărul dat. Util pentru implementarea unui registru de deplasare în stil ring-buffer:

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

take() este forma explicită a indexării avansate (fancy indexing) – alege elemente la indici arbitrari:

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. Filtrare și editări structurale

compress() este forma explicită a indexării booleene – returnează feliile din a selectate de condiția booleană:

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

delete() returnează o copie cu intrările de la indicii dați eliminate:

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

diff() returnează diferența discretă progresivă de ordinul n a tabloului de-a lungul unei axe. Folosită pentru a calcula modificările de prim ordin între eșantioane adiacente:

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. Cât costă fiecare operație

Aproape fiecare funcție de pe această pagină returnează un tablou nou alocat. Două excepții:

  • sort() sortează pe loc; funcția liberă sort() returnează o copie sortată.

  • take() acceptă un cuvânt-cheie out= pentru a scrie într-un tampon (buffer) care există deja.

Într-o buclă care rulează de multe ori pe secundă, preferă sort() pe loc și reutilizează tampoane prealocate peste tot. Măștile booleene în sine sunt alocate de fiecare dată când rulează comparația – construiește o mască o singură dată și reutilizeaz-o între operații în loc să o reconstruiești în interiorul fiecărei iterații.