Un tableau contigu est juste un tableau stocké dans un bloc de mémoire ininterrompu: pour accéder à la valeur suivante du tableau, nous passons simplement à l'adresse mémoire suivante.
Considérez le tableau 2D arr = np.arange(12).reshape(3,4)
. Cela ressemble à ceci:
Dans la mémoire de l'ordinateur, les valeurs de arr
sont stockées comme ceci:
Cela signifie qu'il arr
s'agit d'un tableau contigu en C car les lignes sont stockées en tant que blocs contigus de mémoire. L'adresse mémoire suivante contient la valeur de ligne suivante sur cette ligne. Si nous voulons descendre d'une colonne, il suffit de sauter par-dessus trois blocs (par exemple, sauter de 0 à 4 signifie que nous sautons 1,2 et 3).
Transposer le tableau avec arr.T
signifie que la contiguïté C est perdue car les entrées de ligne adjacentes ne sont plus dans des adresses mémoire adjacentes. Cependant, Fortranarr.T
est-il contigu puisque les colonnes sont dans des blocs de mémoire contigus:
En termes de performances, accéder à des adresses mémoire qui sont côte à côte est très souvent plus rapide que d'accéder à des adresses qui sont plus «étalées» (la récupération d'une valeur dans la RAM peut entraîner la récupération et la mise en cache d'un certain nombre d'adresses voisines pour le CPU.) signifie que les opérations sur des tableaux contigus seront souvent plus rapides.
En raison de la disposition de la mémoire contiguë C, les opérations par ligne sont généralement plus rapides que les opérations par colonne. Par exemple, vous constaterez généralement que
np.sum(arr, axis=1) # sum the rows
est légèrement plus rapide que:
np.sum(arr, axis=0) # sum the columns
De même, les opérations sur les colonnes seront légèrement plus rapides pour les tableaux contigus Fortran.
Enfin, pourquoi ne pouvons-nous pas aplatir le tableau contigu Fortran en attribuant une nouvelle forme?
>>> arr2 = arr.T
>>> arr2.shape = 12
AttributeError: incompatible shape for a non-contiguous array
Pour que cela soit possible, NumPy devrait rassembler les lignes de arr.T
comme ceci:
(La définition de l' shape
attribut suppose directement l'ordre C - c'est-à-dire que NumPy essaie d'effectuer l'opération par ligne.)
C'est impossible à faire. Pour tout axe, NumPy doit avoir une longueur de pas constante (le nombre d'octets à déplacer) pour accéder à l'élément suivant du tableau. L'aplatissement arr.T
de cette manière nécessiterait de sauter en avant et en arrière dans la mémoire pour récupérer des valeurs consécutives du tableau.
Si nous écrivions à la arr2.reshape(12)
place, NumPy copierait les valeurs de arr2 dans un nouveau bloc de mémoire (car il ne peut pas renvoyer une vue sur les données d'origine pour cette forme).
arr2
en forme 1D(12,)
utilise l'ordre C, ce qui signifie que cet axe 1 est déroulé avant l'axe 0 (c'est-à-dire que chacune des quatre lignes doit être placée l'une à côté de l'autre pour créer le tableau 1D souhaité). Il est impossible de lire cette séquence d'entiers (0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11) hors du tampon en utilisant une longueur de foulée constante (les octets à sauter pour visiter ces éléments dans l'ordre seraient 4, 4, -7, 4, 4, -7, 4, 4, 7, 4, 4). NumPy nécessite une longueur de foulée continue par axe.arr[:, ::-1]
est une vue du même tampon mémoire quearr
, NumPy ne le considère pas dans l'ordre C ou F car il a traversé les valeurs dans le tampon dans un ordre "non standard" ...Peut-être que cet exemple avec 12 valeurs de tableau différentes aidera:
Les
C order
valeurs sont dans l'ordre dans lequel elles ont été générées. Les valeurs transposées ne sont pasVous pouvez obtenir des vues 1d des deux
la forme de
x
peut également être modifiée.Mais la forme de la transposition ne peut pas être modifiée. Le
data
est toujours dans l'0,1,2,3,4...
ordre, qui n'est pas accessible comme0,4,8...
dans un tableau 1d.Mais une copie de
x1
peut être modifiée:Regarder
strides
peut également aider. Un pas est la distance (en octets) qu'il doit parcourir pour atteindre la valeur suivante. Pour un tableau 2D, il y aura 2 valeurs de foulée:Pour accéder à la ligne suivante, étape 16 octets, colonne suivante uniquement 4.
Transposer change simplement l'ordre des foulées. La ligne suivante ne fait que 4 octets, c'est-à-dire le numéro suivant.
Changer la forme change également les foulées - il suffit de parcourir le tampon 4 octets à la fois.
Même s'il
x2
ressemblex1
, il a son propre tampon de données, avec les valeurs dans un ordre différent. La colonne suivante a maintenant 4 octets au-dessus, tandis que la ligne suivante est 12 (3 * 4).Et comme avec
x
, changer la forme en 1d réduit les foulées à(4,)
.Pour
x1
, avec des données dans le0,1,2,...
ordre, il n'y a pas de foulée 1d qui donnerait0,4,8...
.__array_interface__
est un autre moyen utile d'afficher les informations du tableau:L'
x1
adresse du tampon de données sera la même que pourx
, avec laquelle il partage les données.x2
a une adresse de tampon différente.Vous pouvez également essayer d'ajouter un
order='F'
paramètre aux commandescopy
etreshape
.la source