6.7. Pogledi i kopije

Pogled je drugi prozor na isti blok podataka kao izvor. Nikakvi podaci se ne kopiraju; pogled drži svjež deskriptor (vlastiti oblik, korake i dtype) ali dijeli međuspremnik. Pogledi su u biti besplatni.

Kopija traži od kamere novi međuspremnik i prolazi kroz izvor ispunjavajući ga. Kopije koštaju i vrijeme i RAM.

Većina metoda za mijenjanje oblika proizvodi poglede. Većina onih koje transformiraju podatke proizvodi kopije. Znanje koja je koja odlučuje hoće li vruća petlja iscrpsti RAM kamere.

6.7.1. Reshape

reshape() vraća polje traženog oblika. Ukupan broj elemenata mora ostati nepromijenjen ili se izaziva ValueError

a = np.arange(12, dtype=np.uint8)
m = a.reshape((3, 4))

Rezultat je pogled – m i a dijele podatke. Pisanje kroz m[0, 0] = 99 mijenja i a[0].

Dodjeljivanje nove n-torke atributu shape je kratica za istu operaciju:

a = np.arange(9)
a.shape = (3, 3)

6.7.2. Transpose

transpose() (ili prečac .T) obrće osi. Implementirano obrtanjem koraka – nikakvi podaci se ne pomiču:

m = np.arange(6, dtype=np.uint8).reshape((2, 3))
t = m.T                  # shape (3, 2), shares m's buffer

Transponirani pogled ne hoda kroz blok podataka kontinuirano. Čitanje t gore redak po redak posjećuje memorijske pozicije 0, 3, 1, 4, 2, 5, a ne temeljni redoslijed 0, 1, 2, 3, 4, 5 u kojem su bajtovi raspoređeni. Obična aritmetika i redukcije s time se nose dobro – koraka ju kroz korake – ali tobytes() ne može, jer vraća temeljni međuspremnik izravno bez kopiranja. Bajtovi koje međuspremnik drži ne odgovaraju redoslijedu koji implicira oblik pogleda, pa metoda izaziva ValueError na bilo kojem nekontinuiranom pogledu. Kada su bajtovi potrebni u transponiranom redoslijedu, prvo iznudite svježu kontinuiranu kopiju:

bytes_out = t.copy().tobytes()

6.7.3. Flatten i flat

flatten() vraća 1-D kopiju polja:

f = m.flatten()          # new dense 1-D ndarray

Proslijedite order='C' (zadano) za hod posljednjom osi prvo ili order='F' za hod prvom osi prvo:

m = np.arange(6, dtype=np.uint8).reshape((2, 3))
# m = [[0, 1, 2],
#      [3, 4, 5]]
m.flatten()              # array([0, 1, 2, 3, 4, 5], dtype=uint8)
m.flatten(order='F')     # array([0, 3, 1, 4, 2, 5], dtype=uint8)

flat je iteratorski oblik. Daje svaki element ndarray bilo kojeg ranga kao skalare, bez alociranja plosnate kopije:

for x in m.flat:
    print(x)

Kada aplikacija treba proći kroz svaki element, preferirajte flat; kada treba gusti 1-D međuspremnik za predaju drugoj funkciji, koristite flatten().

6.7.4. Iteracija

Iteriranje 1-D polja daje skalare; iteriranje polja višeg ranga daje (n-1)-D poglede:

m = np.array([[0, 1, 2], [3, 4, 5]], dtype=np.uint8)
for row in m:
    print(row)               # array([0, 1, 2]), array([3, 4, 5])

Retci koje daje iteriranje matrice su pogledi, pa njihovo mijenjanje mijenja izvor.

6.7.5. Kopije

copy() je eksplicitan način dobivanja neovisnog ndarray čije izmjene ne utječu na original. Alocira se novi međuspremnik i izvor se prolazi u njega:

c = a.copy()

tobytes() vraća bytearray koji dijeli memoriju s blokom podataka polja. Pisanja kroz bytearray mijenjaju polje na licu mjesta. Izaziva ValueError ako polje nije gusto (rezani pogled, transponiranje, …).

tolist() vraća sadržaj kao moguće ugniježđenu Python list. Korisno za serijalizaciju malih rezultata; skupo za velike, jer svaki element postaje zasebni Python objekt.

6.7.6. Koje operacije vraćaju što

Potpuno pravilo:

Sljedeće operacije vraćaju poglede:

  • rezanje – a[1:5], a[::2], m[:, 0];

  • indeksiranje po jednoj osi polja višeg ranga – m[0];

  • iteriranje n-D polja;

  • reshape(), kada je traženi raspored kompatibilan;

  • transpose() / .T;

  • frombuffer();

  • asarray(), kada se dtype podudara.

Sljedeće operacije vraćaju kopije:

Posegnite za eksplicitnom kopijom samo kada je doista potreban neovisan međuspremnik. Na kameri s ograničenim RAM-om, razlika između pogleda i kopije često je razlika između koda koji stane i koda koji ne stane.