6.3. Crearea tablourilor

Fiecare exemplu din restul acestor pagini pornește cu un ndarray deja la îndemână. Această pagină este catalogul modurilor în care apare acel tablou. Există patru familii de constructori:

  • Dintr-un iterabil Python – forma obișnuită de literal / listă / tuplu.

  • Pre-completat la o formă dată – zerouri, unu, o valoare constantă, o matrice identitate.

  • Generat ca o secvență – valori într-un interval sau uniform distanțate.

  • Împachetând un tampon (buffer) deja în RAM – cazul perifericelor.

Fiecare constructor acceptă un cuvânt-cheie dtype= și are valoarea implicită float. Datele de la senzori cer aproape întotdeauna un dtype mai mic decât cel implicit.

Fiecare exemplu de mai jos pornește cu:

from ulab import numpy as np

6.3.1. Dintr-un iterabil Python

array() construiește un ndarray din orice iterabil de numere:

a = np.array([1, 2, 3, 4])
print(a)

Ieșire:

array([1.0, 2.0, 3.0, 4.0], dtype=float)

Iterabilele imbricate produc tablouri multidimensionale. Iterabilele interioare trebuie să aibă toate aceeași lungime, altfel se generează ValueError

m = np.array([[1, 2, 3],
              [4, 5, 6]], dtype=np.uint8)

Un ndarray deja existent este de asemenea o intrare validă; array() copiază întotdeauna. Pentru a evita copierea atunci când nu este necesară, folosiți asarray()

b = np.asarray(a, dtype=np.float)   # same dtype -> no copy

6.3.2. Pre-completat la o formă dată

Când forma țintă este cunoscută, dar conținutul nu este încă, alocați tamponul (buffer) în avans și scrieți în el mai târziu:

  • zeros() – completat cu zerouri.

  • ones() – completat cu unu.

  • full() – completat cu o valoare dată.

  • empty() – alias pentru zeros() (ulab nu lasă tamponul (buffer) neinițializat).

  • eye() – matrice de tip identitate N-pe-M cu unu pe diagonala a k-a.

  • diag() – o matrice diagonală dintr-un vector, sau diagonala unei matrice.

np.zeros((3, 3))                   # 3x3 of zeros
np.ones(5, dtype=np.uint8)         # length-5 vector of ones
np.full((2, 3), 7, dtype=np.int8)  # 2x3, all 7
np.eye(4)                          # 4x4 identity
np.diag([1, 2, 3])                 # 3x3, [1, 2, 3] on the diagonal

Argumentul shape este fie un singur număr întreg (pentru un tablou 1-D), fie un tuplu.

6.3.3. Generat ca o secvență

  • arange() – valori uniform distanțate ca la funcția încorporată range(), dar returnând întotdeauna un ndarray

    np.arange(0, 10, 2)            # array([0, 2, 4, 6, 8])
    
  • linspace()num puncte uniform distanțate între două limite, cu limita superioară inclusă când endpoint=True

    np.linspace(0, 1, num=11)      # 0.0, 0.1, ..., 1.0
    
  • logspace() – puncte distanțate geometric. start și stop sunt exponenți, nu capete; rezultatul merge de la base ** start la base ** stop

    np.logspace(0, 3, num=4)       # 1.0, 10.0, 100.0, 1000.0
    
  • meshgrid() – construiește două matrice de coordonate din două tablouri 1-D, astfel încât o funcție per-pixel f(x, y) să poată fi evaluată pe o întreagă grilă într-un singur apel vectorizat. Având un vector x de lungime W și un vector y de lungime H, meshgrid returnează două matrice H-pe-W: X este vectorul x repetat pe fiecare rând, Y este vectorul y repetat pe fiecare coloană, astfel încât X[i, j] este coordonata x și Y[i, j] este coordonata y a celulei de pe rândul i și coloana j

    x = np.arange(4)            # [0, 1, 2, 3]
    y = np.arange(3)            # [0, 1, 2]
    X, Y = np.meshgrid(x, y)
    # X = [[0, 1, 2, 3],
    #      [0, 1, 2, 3],
    #      [0, 1, 2, 3]]
    # Y = [[0, 0, 0, 0],
    #      [1, 1, 1, 1],
    #      [2, 2, 2, 2]]
    

    f(X, Y) evaluează apoi funcția în fiecare celulă a grilei într-o singură expresie. O hartă a distanței față de centru pe un cadru (H, W), de exemplu, este np.sqrt((X - cx)**2 + (Y - cy)**2) aplicată matricelor returnate de meshgrid().

6.3.4. Îmbinarea

concatenate() îmbină un tuplu de tablouri de-a lungul unei axe existente:

a = np.array([[1, 2], [3, 4]], dtype=np.uint8)
b = np.array([[5, 6]],         dtype=np.uint8)
np.concatenate((a, b), axis=0)
# array([[1, 2], [3, 4], [5, 6]], dtype=uint8)

Toate intrările trebuie să aibă același dtype și ndim și să se potrivească pe fiecare axă în afară de cea de îmbinare. concatenate() alocă un tablou nou suficient de mare cât să cuprindă fiecare intrare și copiază datele în el, deci este instrumentul potrivit pentru îmbinarea unică a unor tablouri care deja există; este instrumentul greșit într-o buclă de fluxuri continue, unde tiparul este pre-alocarea destinației o singură dată și scrierea în ea prin atribuire pe felii.

6.3.5. Împachetarea unui tampon existent

Cel mai util constructor pe o cameră este frombuffer(). El reinterpretează un tampon (buffer) existent de tip bytes ca un ndarray 1-D fără a copia niciun octet:

buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf

Scrierile prin audio sunt vizibile în buf și invers. dtype-ul ales trebuie să dividă uniform lungimea tamponului.

offset= sare peste un antet de la începutul tamponului; count= limitează câte elemente sunt citite:

np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)

Acesta este constructorul potrivit ori de câte ori un periferic predă aplicației un tampon brut – probe de la ADC într-un bytearray, o încărcătură utilă extrasă dintr-un SPI. Octeții pe care i-a scris perifericul sunt tabloul.

Când un periferic scrie valori pe mai mulți octeți într-o ordine a octeților pe care CPU-ul camerei nu o citește nativ, byteswap() inversează ordinea octeților fiecărui element, astfel încât valorile să fie citite corect. Returnează implicit un tablou nou; transmiterea inplace=True modifică sursa pe loc.

frombuffer() gestionează doar dtype-urile pe care numpy le definește el însuși. Pentru perifericele care produc probe de numere întregi pe 32 de biți, from_int32_buffer() și funcțiile înrudite convertesc în float într-o singură trecere.