Dans les opérations entre les tableaux NumPy ( 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 ), chaque 𝐬𝐡𝐚𝐩𝐞 est automatiquement converti pour être identique par diffusion.
Cet article décrit le contenu suivant.
- Règles de diffusion dans NumPy
- Exemples de diffusion dans NumPy
- Exemples de tableaux 2D
- Exemples de tableaux 3D
- Cas qui ne peuvent pas être diffusés
- Fonctions pour obtenir le tableau diffusé
- Diffuseur un tableau vers une forme spécifiée :
- Diffuseur plusieurs tableaux : 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚 𝐬𝐭_𝐚𝐫𝐫𝐚𝐲𝐬()
La documentation officielle explique la diffusion est ci-dessous.
Utilisez 𝐫𝐞𝐬𝐡𝐚𝐩𝐞() ou 𝐧𝐩.𝐧𝐞𝐰𝐚𝐱𝐢𝐬 si vous souhaitez rénover 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 dans la forme de votre choix.
- NumPy : Comment utiliser reshape() et la signification de -1
- NumPy : ajouter de nouvelles dimensions à ndarray (np.newaxis, np.expand_dims)
Règles de diffusion dans NumPy
Il existe les deux règles suivantes pour la diffusion dans NumPy.
- Faites en sorte que les deux tableaux aient le même nombre de dimensions.
- Si les nombres de dimensions des deux tableaux sont différents, ajoutez de nouvelles dimensions de taille 1 à la tête du tableau avec la plus petite dimension.
- Faites en sorte que chaque dimension des deux tableaux ait la même taille.
- Si les tailles de chaque dimension des deux tableaux ne correspondent pas, les dimensions de taille 1 sont étendues à la taille de l’autre tableau.
- S’il existe une dimension dont la taille n’est pas 1 dans l’un des deux tableaux, elle ne peut pas être diffusée et une erreur est générée.
Notez que le nombre de dimensions de 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 peut être obtenu avec l’attribut 𝐧𝐝𝐢𝐦 et la forme avec l’attribut 𝐬𝐡𝐚𝐩𝐞 .
Exemples de diffusion dans NumPy
Exemples de tableaux 2D
Tableau 2D et tableau 1D
Les tableaux 2D et 1D suivants sont utilisés comme exemples. Pour faciliter la compréhension du résultat de la diffusion, l’un d’eux utilise 𝐳𝐞𝐫𝐨𝐬() pour définir tous les éléments sur 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 virgule d’un tableau 1D est (3,) au lieu de (3) car les tuples avec un élément ont une virgule à la fin.
Le résultat de l’addition de ces deux 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 est le suivant.
print(a + b) # [[0 1 2] # [0 1 2] # [0 1 2]]
Transformons le tableau avec un plus petit nombre de dimensions (tableau 1D 𝐛 ) selon les règles décrites ci-dessus.
Tout d’abord, selon la règle 1, le tableau est transformé de la forme (3,) à (1, 3) en ajoutant une nouvelle dimension de taille 1 à la tête. La méthode 𝐫𝐞𝐬𝐡𝐚𝐩𝐞() est utilisée.
b_1_3 = b.reshape(1, 3) print(b_1_3) # [[0 1 2]] print(b_1_3.shape) # (1, 3)
Ensuite, la taille de chaque dimension est étirée conformément à la règle 2. Le tableau est étiré de (1, 3) à (3, 3) . La partie étirée est une copie de la partie d’origine. 𝐧𝐩.𝐭𝐢𝐥𝐞() est utilisé.
print(np.tile(b_1_3, (3, 1))) # [[0 1 2] # [0 1 2] # [0 1 2]]
Notez que 𝐫𝐞𝐬𝐡𝐚𝐩𝐞() et 𝐧𝐩.𝐭𝐢𝐥𝐞() sont utilisés ici à des fins d’explication, mais si vous souhaitez obtenir le tableau diffusé, il existe les fonctions 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚𝐬𝐭_𝐭𝐨() et 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚 𝐬𝐭_𝐚𝐫𝐫𝐚𝐲𝐬() à cette fin. Voir ci-dessous.
Tableau 2D et tableau 2D
Le résultat de l’addition avec le tableau 2D de (3, 1) est le suivant.
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]]
Dans ce cas, comme le nombre de dimensions est déjà le même, le tableau est étiré de (3, 1) à (3, 3) selon la règle 2.
print(np.tile(b_3_1, (1, 3))) # [[0 0 0] # [1 1 1] # [2 2 2]]
Dans les exemples précédents, un seul des tableaux est converti, mais il existe des cas où les deux sont convertis par diffusion.
Voici le résultat de l’ajout de tableaux dont les formes sont (1, 3) et (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]]
(1, 3) et (3, 1) sont tous deux tirés en (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]]
Il en va de même si l’un d’entre eux est un tableau 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]]
Le tableau 1D est converti comme (4,) -> (1, 4) -> (3, 4) et le tableau 2D comme (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]]
Notez que la dimension est étirée uniquement lorsque la taille d’origine est de 1. Sinon, elle ne peut pas être diffusée et une erreur est générée, comme décrit ci-dessous.
Exemples de tableaux 3D
La règle 1 s’applique même si la différence dans le nombre de dimensions est de deux ou plus.
En utilisant des tableaux 3D et 1D comme exemples, les résultats de l’addition sont les suivants :
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 forme est modifiée comme (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]]]
Cas qui ne peuvent pas être diffusés
Comme mentionné ci-dessus, la dimension n’est étirée que si la taille d’origine est 1. Si les tailles des dimensions sont différentes et que les tailles des deux tableaux ne sont pas 1 , la diffusion ne peut pas avoir lieu et une erreur est générée.
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)
Il en va de même pour le cas suivant.
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,)
Dans cet exemple, si une nouvelle dimension est ajoutée à la fin, le tableau peut être diffusé.
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]]]
Il est facile de comprendre si la diffusion peut être effectuée ou non en cliquant sur 𝐬𝐡𝐚𝐩𝐞alignée à droite .
Not broadcastable:< (2, 3, 4)< ( 3) Broadcastable:< (2, 3, 4)< ( 3, 1) -> (1, 3, 1) -> (2, 3, 4)/code>
Si les tailles sont différentes lorsqu'elles sont alignées à droite et comparées verticalement, l'une d'entre elles doit être égale à 1 pour être diffusée.
Par exemple, dans le cas des images, une image couleur est un tableau 3D dont la forme est (𝐡𝐞𝐢𝐠𝐡𝐭, 𝐰𝐢𝐝𝐭𝐡, 3) ( 3 signifie rouge, vert et bleu), tandis qu'une image en niveaux de gris est un tableau 2D dont la forme est (𝐡𝐞𝐢𝐠𝐡𝐭, 𝐰𝐢𝐝𝐭𝐡) .
Dans le cas du calcul de la valeur de chaque couleur dans une image couleur et de la valeur d'une image en niveaux de gris, il est impossible de diffuser même si 𝐡𝐞𝐢𝐠𝐡𝐭 et 𝐰𝐢𝐝𝐭𝐡 sont les pareil.
Vous devez ajouter une dimension à la fin de l'image en niveaux de gris avec 𝐧𝐩.𝐧𝐞𝐰𝐚𝐱𝐢𝐬 , 𝐧𝐩.𝐞𝐱𝐩𝐚𝐧𝐝_𝐝𝐢𝐦𝐬() , et ainsi de suite.
Not broadcastable:< (h, w, 3)< ( h, w) Broadcastable:< (h, w, 3)< (h, w, 1) -> (h, w, 3)/code>
Fonctions pour obtenir le tableau diffusé
Diffuseur un tableau vers une forme spécifiée :
Utilisez 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚𝐬𝐭_𝐭𝐨() pour diffuser 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 avec le 𝐬𝐡𝐚𝐩𝐞 spécifique .
Le premier argument est le 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 d'origine et le second est un tuple ou une liste indiquant 𝐬𝐡𝐚𝐩𝐞 . Le 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 diffusé est renvoyé.
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'>
Une erreur se produit lors de la spécification d'une forme qui ne peut pas être diffusée.
# 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)
Diffuseur plusieurs tableaux : 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚 𝐬𝐭_𝐚𝐫𝐫𝐚𝐲𝐬()
Utiliser 𝐧𝐩.𝐛𝐫𝐨𝐚𝐝𝐜𝐚 𝐬𝐭_𝐚𝐫𝐫𝐚𝐲𝐬() pour diffuseur plusieurs 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 .
Spécifiez plusieurs tableaux séparés par des virgules. Une liste de 𝐧𝐝𝐚𝐫𝐫𝐚𝐲 est renvoyée.
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'>
Une erreur se produit lors de la spécification d'une combinaison de tableaux qui ne peuvent pas être diffusés.
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