Copie și vedere (copy vs view) în NumPy

Explică diferența dintre o vedere (aceleași date) și o copie în NumPy și cum le recunoști cu .base și np.shares_memory.

Sintaxă
b = a.copy()
b.base
np.shares_memory(a, b)

Ce face Copie și vedere (copy vs view)

O vedere (view) este un tablou nou care folosește aceeași memorie cu tabloul inițial: dacă schimbi un element în vedere, se schimbă și în original. Slicing-ul (a[1:3]), reshape(), .T și de obicei ravel() dau vederi. Asta economisește memorie și timp.

O copie are datele ei. Indexarea cu liste de indici, măștile booleene, flatten(), astype() și .copy() dau copii.

Atributul b.base arată tabloul de la care vine o vedere (sau None pentru un tablou cu date proprii). np.shares_memory(a, b) (din NumPy 1.11) spune direct dacă două tablouri folosesc aceeași memorie.

Parametri

Parametru Descriere
a, b La np.shares_memory: cele două tablouri comparate.

Ce returnează

copy(): un tablou nou, independent. np.shares_memory: True sau False. .base: tabloul de bază sau None.

Exemple

Exemplul 1: Slicing-ul dă o vedere

Am modificat doar bucata, dar valoarea apare și în note.

import numpy as np

note = np.array([9, 7, 10, 8, 6])
bucata = note[1:3]
bucata[0] = 100
print(note)
print(bucata.base is note)

Rezultat

[  9 100  10   8   6]
True

Exemplul 2: .copy() pentru date separate

import numpy as np

note = np.array([9, 7, 10, 8, 6])
copie = note[1:3].copy()
copie[0] = 100
print(note)
print(copie)
print(copie.base)

Rezultat

[ 9  7 10  8  6]
[100  10]
None

Exemplul 3: Ce dă vedere și ce dă copie

import numpy as np

a = np.arange(6)
operatii = {
    "a[1:4]": a[1:4],
    "a.reshape(2, 3)": a.reshape(2, 3),
    "a[[0, 2]]": a[[0, 2]],
    "a[a > 2]": a[a > 2],
    "a.astype(float)": a.astype(float),
}
for nume, rezultat in operatii.items():
    print(f"{nume:17} -> memorie comună: {np.shares_memory(a, rezultat)}")

Rezultat

a[1:4]            -> memorie comună: True
a.reshape(2, 3)   -> memorie comună: True
a[[0, 2]]         -> memorie comună: False
a[a > 2]          -> memorie comună: False
a.astype(float)   -> memorie comună: False

Greșeli frecvente

  • Faci b = a și crezi că ai o copie. Este același tablou, cu alt nume; folosește b = a.copy().
  • Iei o bucată mică dintr-un tablou foarte mare și păstrezi doar bucata. Vederea ține tot tabloul mare în memorie; .copy() eliberează restul.
  • Te bazezi pe b.base is a după mai multe operații. base poate arăta spre tabloul inițial, nu spre cel intermediar; np.shares_memory este mai sigur.

Comenzi înrudite

  • Indexare și slicing: Accesează un element, o bucată, un rând sau o coloană dintr-un tablou NumPy cu paranteze pătrate.
  • ndarray.ravel() și flatten(): Transformă un tablou cu mai multe dimensiuni într-unul 1D: ravel dă o vedere când poate, flatten dă mereu o copie.
  • ndarray.reshape(): Schimbă forma unui tablou (de exemplu din 12 elemente în 3 x 4) fără să-i schimbe datele.
  • Indexare cu liste de indici: Selectează mai multe elemente, rânduri sau coloane deodată, dând o listă de poziții (fancy indexing).