
Nelle operazioni tra gli array NumPy (ndarray), ogni forma viene automaticamente convertita in modo che sia la stessa tramite la trasmissione.
In questo articolo vengono descritti i seguenti contenuti.
- Regole di trasmissione in NumPy
- Esempi di trasmissione in NumPy
- Esempi di array 2D
- Esempi di array 3D
- Casi che non possono essere trasmessi
- Funzioni per ottenere l’array trasmesso
- Trasmetti un array a una forma specificata.:
np.broadcast_to()
- Trasmetti più matrice:
np.broadcast_arrays()
- Trasmetti un array a una forma specificata.:
La documentazione ufficiale che spiega la trasmissione è di seguito.
Usa reshape() o np.newaxis se vuoi rimodellare ndarray in qualsiasi forma tu voglia.
Regole di trasmissione in NumPy
Ci sono le seguenti due regole per la trasmissione in NumPy.
- Fai in modo che i due array hanno lo stesso numero di dimensioni.
- Se i numeri delle dimensioni delle due matrici sono diversi, aggiungi nuove dimensioni con dimensione 1 all’inizio della matrice con la dimensione più piccola.
- Rendi ciascuna dimensione delle due matrici della stessa dimensione.
- Se le dimensioni di ciascuna delle due matrici non corrispondono, le dimensioni con dimensione 1 vengono estese alla dimensione dell’altra matrice.
- Se è presente una dimensione la cui dimensione non è 1 in nessuno dei due array, non può essere trasmesso e viene generato un errore.
Si noti che il numero di dimensioni di ndarray può essere ottenuto con l’attributo ndim e la forma con l’attributo shape.
Esempi di trasmissione in NumPy
Esempi di array 2D
Matrice 2D e matrice 1D
I seguenti array 2D e 1D sono usati come esempi. Per facilitare la comprensione del risultato della trasmissione, uno di loro usa zeros() per impostare tutti gli elementi su 0.
import numpy as np
a = np.zeros((3, 3), np.int)
print(a)
# [[0 0 0]
# [0 0 0]
# [0 0 0]]
print(a.shape)
# (3, 3)
b = np.arange(3)
print(b)
# [0 1 2]
print(b.shape)
# (3,)
La forma dell’array 1D è (3,) invece di (3) perché le tuple con un elemento hanno una virgola alla fine.
Il risultato dell’aggiunta di questi due ndarray è il seguente.
print(a + b)
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
Trasformiamo l’array con un numero di dimensioni minore (array 1D b) secondo le regole sopra l’altro.
Innanzitutto, secondo la regola 1, l’array viene trasformato dalla forma (3,) a (1, 3) aggiungendo una nuova dimensione di dimensione 1 alla testa. Viene utilizzato il metodo reshape().
b_1_3 = b.reshape(1, 3)
print(b_1_3)
# [[0 1 2]]
print(b_1_3.shape)
# (1, 3)
Successivamente, la dimensione di ciascuna dimensione viene allungata secondo la regola 2. L’array viene allungato da (1, 3) a (3, 3). La parte allungata è una copia della parte originale. np.tile() viene utilizzato.
print(np.tile(b_1_3, (3, 1)))
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
Nota che reshape() e np.tile() sono usati qui per motivi di spiegazione, ma se vuoi ottenere l’array trasmesso, ci sono funzioni np.broadcast_to() e np.broadcast_arrays() per quello scopo. Vedi sotto.
Matrice 2D e matrice 2D
Il risultato dell’addizione con l’array 2D di (3, 1) è il seguente.
b_3_1 = b.reshape(3, 1)
print(b_3_1)
# [[0]
# [1]
# [2]]
print(b_3_1.shape)
# (3, 1)
print(a + b_3_1)
# [[0 0 0]
# [1 1 1]
# [2 2 2]]
In questo caso, poiché il numero di dimensioni è già lo stesso, l’array viene allungato da (3, 1) a (3, 3) secondo la regola 2.
print(np.tile(b_3_1, (1, 3)))
# [[0 0 0]
# [1 1 1]
# [2 2 2]]
Negli esempi precedenti, viene convertito solo uno degli array, ma ci sono casi in cui entrambi vengono convertiti tramite trasmissione.
Quanto segue è il risultato dell’aggiunta di matrici le cui forme sono (1, 3) e (3, 1).
print(b_1_3)
# [[0 1 2]]
print(b_1_3.shape)
# (1, 3)
print(b_3_1)
# [[0]
# [1]
# [2]]
print(b_3_1.shape)
# (3, 1)
print(b_1_3 + b_3_1)
# [[0 1 2]
# [1 2 3]
# [2 3 4]]
Sia (1, 3) che (3, 1) sono allungati a (3, 3).
print(np.tile(b_1_3, (3, 1)))
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
print(np.tile(b_3_1, (1, 3)))
# [[0 0 0]
# [1 1 1]
# [2 2 2]]
print(np.tile(b_1_3, (3, 1)) + np.tile(b_3_1, (1, 3)))
# [[0 1 2]
# [1 2 3]
# [2 3 4]]
Lo stesso vale se uno di questi è un array 1D.
c = np.arange(4)
print(c)
# [0 1 2 3]
print(c.shape)
# (4,)
print(b_3_1)
# [[0]
# [1]
# [2]]
print(b_3_1.shape)
# (3, 1)
print(c + b_3_1)
# [[0 1 2 3]
# [1 2 3 4]
# [2 3 4 5]]
L’array 1D viene convertito come (4,) -> (1, 4) -> (3, 4) e l’array 2D come (3, 1) -> (3, 4).
print(np.tile(c.reshape(1, 4), (3, 1)))
# [[0 1 2 3]
# [0 1 2 3]
# [0 1 2 3]]
print(np.tile(b_3_1, (1, 4)))
# [[0 0 0 0]
# [1 1 1 1]
# [2 2 2 2]]
print(np.tile(c.reshape(1, 4), (3, 1)) + np.tile(b_3_1, (1, 4)))
# [[0 1 2 3]
# [1 2 3 4]
# [2 3 4 5]]
Si noti che la dimensione viene allungata solo la dimensione originale è 1. In caso contrario, non può essere trasmesso e viene generato un errore, come deriva di seguito.
Esempi di array 3D
La regola 1 si applica anche se la differenza nel numero di dimensioni è dovuta o più.
Usando gli array 3D e 1D come esempi, i risultati dell’addizione sono i seguenti:
a = np.zeros((2, 3, 4), dtype=np.int)
print(a)
# [[[0 0 0 0]
# [0 0 0 0]
# [0 0 0 0]]
#
# [[0 0 0 0]
# [0 0 0 0]
# [0 0 0 0]]]
print(a.shape)
# (2, 3, 4)
b = np.arange(4)
print(b)
# [0 1 2 3]
print(b.shape)
# (4,)
print(a + b)
# [[[0 1 2 3]
# [0 1 2 3]
# [0 1 2 3]]
#
# [[0 1 2 3]
# [0 1 2 3]
# [0 1 2 3]]]
La forma viene modificata come (4, ) -> (1, 1, 4) -> (2, 3, 4).
b_1_1_4 = b.reshape(1, 1, 4)
print(b_1_1_4)
# [[[0 1 2 3]]]
print(np.tile(b_1_1_4, (2, 3, 1)))
# [[[0 1 2 3]
# [0 1 2 3]
# [0 1 2 3]]
#
# [[0 1 2 3]
# [0 1 2 3]
# [0 1 2 3]]]
Casi che non possono essere trasmessi
Come accennato in precedenza, la dimensione viene allungata solo se la dimensione originale è 1. Se le dimensioni delle dimensioni sono diverse e le dimensioni di entrambi gli array non sono 1, non può essere trasmesso e viene generato un errore.
a = np.zeros((4, 3), dtype=np.int)
print(a)
# [[0 0 0]
# [0 0 0]
# [0 0 0]
# [0 0 0]]
print(a.shape)
# (4, 3)
b = np.arange(6).reshape(2, 3)
print(b)
# [[0 1 2]
# [3 4 5]]
print(b.shape)
# (2, 3)
# print(a + b)
# ValueError: operands could not be broadcast together with shapes (4,3) (2,3)
Lo stesso vale per il caso seguente.
a = np.zeros((2, 3, 4), dtype=np.int)
print(a)
# [[[0 0 0 0]
# [0 0 0 0]
# [0 0 0 0]]
#
# [[0 0 0 0]
# [0 0 0 0]
# [0 0 0 0]]]
print(a.shape)
# (2, 3, 4)
b = np.arange(3)
print(b)
# [0 1 2]
print(b.shape)
# (3,)
# print(a + b)
# ValueError: operands could not be broadcast together with shapes (2,3,4) (3,)
In questo esempio, se alla fine viene aggiunta una nuova dimensione, l’array può essere trasmesso.
b_3_1 = b.reshape(3, 1)
print(b_3_1)
# [[0]
# [1]
# [2]]
print(b_3_1.shape)
# (3, 1)
print(a + b_3_1)
# [[[0 0 0 0]
# [1 1 1 1]
# [2 2 2 2]]
#
# [[0 0 0 0]
# [1 1 1 1]
# [2 2 2 2]]]
È facile capire se può essere trasmesso o meno dalla forma allineata a destra.
NG
(2, 3, 4)
( 3)
OK
(2, 3, 4)
( 3, 1) -> (1, 3, 1) -> (2, 3, 4)
Se le dimensioni sono diverse allineate a destra e confrontate verticalmente, una di esse deve essere 1 per essere trasmesso.
Ad esempio, nel caso delle immagini, un’immagine a colori è un array 3D la cui forma è (altezza, larghezza, 3) (3 significa rosso, verde e blu), mentre un’immagine in scala di grigi è un array 2D la cui forma è (altezza , larghezza).
Nel caso di calcolo dell’altezza di ciascun colore in un’immagine a colori e del valore di un’immagine in scala di grigi, è impossibile trasmettere anche se l’immagine e la larghezza sono le stesse.
È necessario aggiungere una dimensione alla fine dell’immagine in scala di grigi con np.newaxis, np.expand_dims() e così via.
NG
(h, w, 3)
( h, w)
OK
(h, w, 3)
(h, w, 1) -> (h, w, 3)
Funzioni per ottenere l’array trasmesso
Trasmetti un array a una forma specificata.:np.broadcast_to()
Usa np.broadcast_to() per trasmettere ndarray con la forma specificata.
Il primo argomento è il ndarray originale e il secondo è una tupla o una lista che indica la forma. Il ndarray viene trasmesso.
a = np.arange(3)
print(a)
# [0 1 2]
print(a.shape)
# (3,)
print(np.broadcast_to(a, (3, 3)))
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
print(type(np.broadcast_to(a, (3, 3))))
# <class 'numpy.ndarray'>
Si verifica un errore quando si specifica una forma che non può essere trasmesso.
# print(np.broadcast_to(a, (2, 2)))
# ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (3,) and requested shape (2,2)
Trasmetti più matrice:np.broadcast_arrays()
Usa np.broadcast_arrays() per trasmettere più ndarray.
Specificare più array separati da virgole. Viene restituito un elenco di ndarray.
a = np.arange(3)
print(a)
# [0 1 2]
print(a.shape)
# (3,)
b = np.arange(3).reshape(3, 1)
print(b)
# [[0]
# [1]
# [2]]
print(b.shape)
# (3, 1)
arrays = np.broadcast_arrays(a, b)
print(type(arrays))
# <class 'list'>
print(len(arrays))
# 2
print(arrays[0])
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
print(arrays[1])
# [[0 0 0]
# [1 1 1]
# [2 2 2]]
print(type(arrays[0]))
# <class 'numpy.ndarray'>
Si verifica un errore quando si specifica una combinazione di array che non possono essere trasmessi.
c = np.zeros((2, 2))
print(c)
# [[0. 0.]
# [0. 0.]]
print(c.shape)
# (2, 2)
# arrays = np.broadcast_arrays(a, c)
# ValueError: shape mismatch: objects cannot be broadcast to a single shape