Usa una visualizzazione e ottieni runtime gratuito! Estendi n-dim
array generici an+1-dim
Introdotto in NumPy1.10.0
, possiamo sfruttare numpy.broadcast_to
per generare semplicemente una 3D
vista 2D
nell'array di input. Il vantaggio sarebbe l'assenza di sovraccarico di memoria aggiuntivo e il runtime praticamente gratuito. Ciò sarebbe essenziale nei casi in cui gli array sono grandi e possiamo lavorare con le visualizzazioni. Inoltre, questo funzionerebbe con n-dim
casi generici .
Userei la parola stack
al posto di copy
, poiché i lettori potrebbero confonderla con la copia di array che crea copie di memoria.
Impila lungo il primo asse
Se vogliamo impilare l'input arr
lungo il primo asse, la soluzione con cui np.broadcast_to
creare la 3D
vista sarebbe:
np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here
Impila lungo il terzo / ultimo asse
Per impilare l'input arr
lungo il terzo asse, la soluzione per creare la 3D
vista sarebbe:
np.broadcast_to(arr[...,None],arr.shape+(3,))
Se abbiamo effettivamente bisogno di una copia in memoria, possiamo sempre aggiungerla .copy()
lì. Quindi, le soluzioni sarebbero:
np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()
Ecco come funziona l'impilamento per i due casi, mostrato con le informazioni sulla forma per un caso campione:
# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)
# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)
# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)
Le stesse soluzioni funzionerebbero per estendere un n-dim
input per n+1-dim
visualizzare l'output lungo il primo e l'ultimo asse. Esploriamo alcuni casi più scuri -
Caso di input 3D:
In [58]: arr = np.random.rand(4,5,6)
# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)
# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)
Caso di input 4D:
In [61]: arr = np.random.rand(4,5,6,7)
# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)
# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)
e così via.
Tempistiche
Usiamo un 2D
caso campione di grandi dimensioni, otteniamo i tempi e verifichiamo che l'output sia un file view
.
# Sample input array
In [19]: arr = np.random.rand(1000,1000)
Dimostriamo che la soluzione proposta è davvero una vista. Useremo lo stacking lungo il primo asse (i risultati sarebbero molto simili per lo stacking lungo il terzo asse) -
In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True
Prendiamo i tempi per dimostrare che è praticamente gratuito -
In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop
In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop
Essendo una vista, aumentando N
da 3
a 3000
non cambia nulla sui tempi ed entrambi sono trascurabili sulle unità di temporizzazione. Quindi, efficiente sia sulla memoria che sulle prestazioni!
b[:,:,0]
,b[:,:,1]
eb[:,:,2]
. Ogni fetta di terza dimensione è una copia della matrice 2D originale. Questo non è così ovvio solo a guardarloprint(b)
.