Skip to content

NumPy: Determinare se ndarray è vista o copia e se condivide la memoria

Python

È possibile utilizzare l’attributo base per se l’array NumPy numpy.ndarray è una vista o una copia. Inoltre, np.shares_memory() può essere utilizzato per consentire se due array devono essere la memoria.

Questo articolo descrive quanto segue:

  • Visualizza e copia numpy.ndarray
    • Esempio di creazione di una vista
    • Esempio di creazione di una copia
    • copy() e view()
  • Determina se visualizzare o ottenere:base attribute
  • Determina se la memoria è condivisa:np.shares_memory()
    • Utilizzo di base
    • np.may_share_memory()


La versione di NumPy nel codice di esempio seguente è 1.16.4. Si noti che versioni diverse potrebbero comportarsi in modo diverso.

Visualizza e copia numpy.ndarray

Esistono due tipi di numpy.ndarray: recensioni e copy.

Quando si crea un altro oggetto da matrice da un oggetto matrice, l’oggetto che condivide la memoria con l’oggetto originale (si riferisce a parte oa tutta la memoria dell’oggetto originale) viene chiamato vista.

D’altra parte, un oggetto che alloca memoria separatamente dall’oggetto originale viene copiato.

Esempio di creazione di una vista

Ad esempio, le sezioni si creano viste.

import numpy as np

a_2d = np.arange(12).reshape(3, 4)
print(a_2d)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

a_slice = a_2d[:2, :2]
print(a_slice)
# [[0 1]
#  [4 5]]

L’oggetto originale e la vista si appartiene alla stessa memoria, quindi la modifica del valore di un elemento in un oggetto cambia il valore nell’altro.

a_slice[0, 0] = 100
print(a_slice)
# [[100   1]
#  [  4   5]]

print(a_2d)
# [[100   1   2   3]
#  [  4   5   6   7]
#  [  8   9  10  11]]

a_2d[0, 0] = 0
print(a_2d)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(a_slice)
# [[0 1]
#  [4 5]]

Oltre alle sezioni, alcune funzioni e metodi, come reshape(), che verranno utilizzati nell’esempio sezione successiva, restituiscono una vista.

Esempio di creazione di una copia

L’indicizzazione di fantasia crea copie.

a_fancy_index = a_2d[[0, 1]]
print(a_fancy_index)
# [[0 1 2 3]
#  [4 5 6 7]]

Perché non condividere la memoria, la modifica del valore di un oggetto non cambia il valore dell’altro.

a_fancy_index[0, 0] = 100
print(a_fancy_index)
# [[100   1   2   3]
#  [  4   5   6   7]]

print(a_2d)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

copy() e view()

È possibile utilizzare copy() per creare una copia di un oggetto array.

È anche possibile creare una copia della vista.

a_slice_copy = a_2d[:2, :2].copy()
print(a_slice_copy)
# [[0 1]
#  [4 5]]

La modifica del valore di un elemento di un oggetto non modifica il valore dell’altro.

a_slice_copy[0, 0] = 100
print(a_slice_copy)
# [[100   1]
#  [  4   5]]

print(a_2d)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

C’è anche un metodo chiamato view().

Tuttavia, ad esempio, la chiamata a view() da un oggetto creato da un’indicizzazione di fantasia restituirà solo la vista di una copia, non la vista dell’oggetto originale.

Determina se visualizzare o ottenere:base attribute

Usa l’attributo di base per se numpy.ndarray è una vista o una copia (strettamente una vista o meno).

Se numpy.ndarray è una vista, l’attributo base restituisce l’originale numpy.ndarray.

Prendi reshape(), che porta una vista il più possibile, come esempio.

a = np.arange(10)
print(a)
# [0 1 2 3 4 5 6 7 8 9]

a_0 = a[:6]
print(a_0)
# [0 1 2 3 4 5]

a_1 = a_0.reshape(2, 3)
print(a_1)
# [[0 1 2]
#  [3 4 5]]

print(a_0.base)
# [0 1 2 3 4 5 6 7 8 9]

print(a_1.base)
# [0 1 2 3 4 5 6 7 8 9]

L’attributo di base della copia o dell’originale numpy.ndarray (un numpy.ndarray appena creato che non è né una copia né una vista) è Nessuno.

a_copy = a.copy()
print(a_copy)
# [0 1 2 3 4 5 6 7 8 9]

print(a_copy.base)
# None

print(a.base)
# None

È possibile utilizzare l’operatore è per l’attributo di base Nessuno per utilizzare se si tratta di una vista o meno.

print(a_0.base is None)
# False

print(a_copy.base is None)
# True

print(a.base is None)
# True

Puoi anche vedere che vuoi la memoria confrontando l’attributo di base della vista con l’originale numpy.ndarray o confrontando tra loro gli attributi di base della vista.

print(a_0.base is a)
# True

print(a_0.base is a_1.base)
# True

Il seguente np.shares_memory() è conveniente per se la memoria è condivisa.

Determina se la memoria è condivisa:np.shares_memory()

Se i due array devono essere la memoria può essere determinato np.shares_memory().

Utilizzo di base

Specificare numpy.ndarray in np.shares_memory(). True viene restituito se tali array contengono la memoria.

a = np.arange(6)
print(a)
# [0 1 2 3 4 5]

a_reshape = a.reshape(2, 3)
print(a_reshape)
# [[0 1 2]
#  [3 4 5]]

print(np.shares_memory(a, a_reshape))
# True

Se si specificano due viste generate dal comune numpy.ndarray, viene restituito anche True.

a_slice = a[2:5]
print(a_slice)
# [2 3 4]

print(np.shares_memory(a_reshape, a_slice))
# True

In caso di copia, False viene restituito.

a_reshape_copy = a.reshape(2, 3).copy()
print(a_reshape_copy)
# [[0 1 2]
#  [3 4 5]]

print(np.shares_memory(a, a_reshape_copy))
# False

np.may_share_memory()

C’è anche una funzione simile a np.shares_memory() chiamata np.may_share_memory().

np.may_share_memory() è meno rigido di np.shares_memory(), come puoi vedere dal fatto che il nome della funzione contiene maggio.

np.may_share_memory() determina solo se gli intervalli di indirizzi di memoria si sovrappongono, non considera se sono presenti elementi fanno che riferimento alla stessa memoria.

Ad esempio, nel seguente, le due sezioni sono la vista di num.ndarray e si verificano all’intervallo di sovrapposizione, ma ogni elemento stesso fa riferimento a una diversa memoria.

a = np.arange(10)
print(a)
# [0 1 2 3 4 5 6 7 8 9]

a_0 = a[::2]
print(a_0)
# [0 2 4 6 8]

a_1 = a[1::2]
print(a_1)
# [1 3 5 7 9]

np.shares_memory() restituisce False per un giudizio rigoroso, ma np.may_share_memory() restituisce True.

print(np.shares_memory(a_0, a_1))
# False

print(np.may_share_memory(a_0, a_1))
# True

Nell’esempio seguente, np.may_share_memory() aggiunge False perché le due sezioni sono la prima metà e la seconda metà del numpy.ndarray originale e gli non si sovrappongono.

a_2 = a[:5]
print(a_2)
# [0 1 2 3 4]

a_3 = a[5:]
print(a_3)
# [5 6 7 8 9]

print(np.shares_memory(a_2, a_3))
# False

print(np.may_share_memory(a_2, a_3))
# False

Il tempo di elaborazione è più lungo per np.shares_memory(), il che esprime un giudizio rigoroso. Si noti che il codice seguente utilizza il comando magico di Jupyter Notebook %%timeit e non viene misurato quando come eseguire script Python.

%%timeit
np.shares_memory(a_0, a_1)
# 839 ns ± 53.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%%timeit
np.may_share_memory(a_0, a_1)
# 275 ns ± 5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

per np.may_share_memory() possa restituire True per errore quando ogni elemento non condivide la memoria, non ripete False per errore quando la memoria è condivisa.