6.7. Vues et copies¶
Une vue est une seconde fenêtre sur le même bloc de données que la source. Aucune donnée n’est copiée ; la vue détient un nouveau descripteur (sa propre forme, ses pas et son dtype) mais partage le tampon. Les vues sont essentiellement gratuites.
Une copie demande un nouveau tampon à la caméra et parcourt la source pour le remplir. Les copies coûtent à la fois du temps et de la RAM.
La plupart des méthodes qui modifient la forme produisent des vues. La plupart de celles qui transforment les données produisent des copies. Savoir laquelle est laquelle détermine si une boucle critique met la caméra à court de RAM.
6.7.1. Reshape¶
reshape() renvoie un tableau de la forme demandée. Le nombre total d’éléments doit rester inchangé, sinon ValueError est levée
a = np.arange(12, dtype=np.uint8)
m = a.reshape((3, 4))
Le résultat est une vue – m et a partagent leurs données. Écrire via m[0, 0] = 99 change aussi a[0].
Affecter un nouveau tuple à shape est un raccourci pour la même opération
a = np.arange(9)
a.shape = (3, 3)
6.7.2. Transpose¶
transpose() (ou le raccourci .T) inverse les axes. Implémentée en inversant les pas – aucune donnée n’est déplacée
m = np.arange(6, dtype=np.uint8).reshape((2, 3))
t = m.T # shape (3, 2), shares m's buffer
Une vue transposée ne parcourt pas le bloc de données de façon contiguë. Lire t ci-dessus ligne par ligne visite les positions mémoire 0, 3, 1, 4, 2, 5, et non l’ordre sous-jacent 0, 1, 2, 3, 4, 5 dans lequel les octets sont disposés. L’arithmétique et les réductions ordinaires gèrent cela très bien – elles parcourent les pas – mais tobytes() ne le peut pas, car elle renvoie directement le tampon sous-jacent sans copie. Les octets que contient le tampon ne correspondent pas à l’ordre que la forme de la vue implique, donc la méthode lève ValueError sur toute vue non contiguë. Lorsque les octets sont nécessaires dans l’ordre transposé, forcez d’abord une nouvelle copie contiguë
bytes_out = t.copy().tobytes()
6.7.3. Flatten et flat¶
flatten() renvoie une copie 1-D du tableau
f = m.flatten() # new dense 1-D ndarray
Passez order='C' (par défaut) pour parcourir le dernier axe en premier, ou order='F' pour le premier axe en premier
m = np.arange(6, dtype=np.uint8).reshape((2, 3))
# m = [[0, 1, 2],
# [3, 4, 5]]
m.flatten() # array([0, 1, 2, 3, 4, 5], dtype=uint8)
m.flatten(order='F') # array([0, 3, 1, 4, 2, 5], dtype=uint8)
flat est la forme itérateur. Elle produit chaque élément d’un ndarray de rang quelconque sous forme de scalaires, sans allouer de copie aplatie
for x in m.flat:
print(x)
Lorsque l’application a besoin de parcourir chaque élément, préférez flat ; lorsqu’elle a besoin d’un tampon 1-D dense à passer à une autre fonction, utilisez flatten().
6.7.4. Itération¶
Itérer un tableau 1-D produit des scalaires ; itérer un tableau de rang supérieur produit des vues (n-1)-D
m = np.array([[0, 1, 2], [3, 4, 5]], dtype=np.uint8)
for row in m:
print(row) # array([0, 1, 2]), array([3, 4, 5])
Les lignes produites par l’itération d’une matrice sont des vues, donc les modifier modifie la source.
6.7.5. Copies¶
copy() est la façon explicite d’obtenir un ndarray indépendant dont les modifications n’affectent pas l’original. Un nouveau tampon est alloué et la source y est parcourue
c = a.copy()
tobytes() renvoie un bytearray qui partage la mémoire avec le bloc de données du tableau. Les écritures via le bytearray modifient le tableau en place. Lève ValueError si le tableau n’est pas dense (une vue tranchée, une transposée, …).
tolist() renvoie le contenu sous forme de list Python éventuellement imbriquée. Utile pour sérialiser de petits résultats ; coûteux pour les grands, car chaque élément devient un objet Python distinct.
6.7.6. Quelles opérations renvoient quoi¶
La règle complète :
Les opérations suivantes renvoient des vues :
le tranchage –
a[1:5],a[::2],m[:, 0];l’indexation sur un seul axe d’un tableau de rang supérieur –
m[0];l’itération d’un tableau n-D ;
reshape(), lorsque la disposition demandée est compatible ;transpose()/.T;asarray(), lorsque le dtype correspond.
Les opérations suivantes renvoient des copies :
copy();l’indexation booléenne –
a[mask];l’arithmétique –
a + b,a * 2,np.sin(a);array()– copie toujours, même depuis un autre tableau ;
Ne recourez à une copie explicite que lorsqu’un tampon indépendant est réellement nécessaire. Sur une caméra à RAM limitée, la différence entre une vue et une copie est souvent la différence entre du code qui tient et du code qui ne tient pas.