Dans le numpy manual à propos de la fonction reshape (), il est dit
>>> a = np.zeros((10, 2))
# A transpose make the array non-contiguous
>>> b = a.T
# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()
>>> c.shape = (20)
AttributeError: incompatible shape for a non-contiguous array
Mes questions sont:
c.shape = (20)
génère-t-il une erreur incompatible shape for a non-contiguous array
?Merci pour votre réponse!
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 de mémoire suivante.
Considérons 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 que arr
est un tableau C contigu car les lignes sont stockés sous forme de blocs de mémoire contigus. L'adresse mémoire suivante contient la valeur de la ligne suivante sur cette ligne. Si nous voulons descendre d'une colonne, il nous suffit de sauter trois blocs (par exemple, passer 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 lignes adjacentes ne figurent plus dans des adresses mémoire adjacentes. Cependant, arr.T
Est Fortran contigu puisque les colonnes sont dans des blocs de mémoire contigus:
En termes de performances, accéder à des adresses de mémoire adjacentes est très souvent plus rapide que d’accéder à des adresses plus "dispersées" (extraire une valeur de RAM pourrait entraîner la création d’un certain nombre d’adresses voisines). récupéré et mis en cache pour la CPU.) Cela signifie que les opérations sur des tableaux contigus seront souvent plus rapides.
En conséquence de la disposition de la mémoire C contiguë, les opérations ligne par ligne sont généralement plus rapides que les opérations 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 Fortran contigus.
Enfin, pourquoi ne pouvons-nous pas aplatir le tableau contigu de 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 assembler les lignes de arr.T
Comme suit:
(La définition de l’attribut shape
suppose directement l’ordre C: c’est-à-dire que NumPy tente d’effectuer l’opération par rangée.)
C'est impossible à faire. Pour tout axe, NumPy doit avoir une constante longueur de foulée (le nombre d'octets à déplacer) pour accéder à l'élément suivant du tableau. Pour aplatir arr.T
De cette manière, il faudrait sauter en avant et en arrière en mémoire pour récupérer des valeurs consécutives du tableau.
Si nous écrivions plutôt arr2.reshape(12)
, NumPy copierait les valeurs d'arr2 dans un nouveau bloc de mémoire (car il ne peut pas restituer les données d'origine pour cette forme).
Peut-être que cet exemple avec 12 valeurs de tableau différentes aidera:
In [207]: x=np.arange(12).reshape(3,4).copy()
In [208]: x.flags
Out[208]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [209]: x.T.flags
Out[209]:
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : False
...
Le C order
valeurs sont dans l’ordre dans lequel elles ont été générées. Les valeurs transposées ne sont pas
In [212]: x.reshape(12,) # same as x.ravel()
Out[212]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
In [213]: x.T.reshape(12,)
Out[213]: array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
Vous pouvez obtenir une vue 1d des deux
In [214]: x1=x.T
In [217]: x.shape=(12,)
la forme de x
peut également être modifiée.
In [220]: x1.shape=(12,)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-220-cf2b1a308253> in <module>()
----> 1 x1.shape=(12,)
AttributeError: incompatible shape for a non-contiguous array
Mais la forme de la transposition ne peut pas être modifiée. Le data
est toujours dans le 0,1,2,3,4...
ordre, auquel on ne peut accéder par 0,4,8...
dans un tableau 1d.
Mais une copie de x1
peut être changé:
In [227]: x2=x1.copy()
In [228]: x2.flags
Out[228]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [229]: x2.shape=(12,)
Regarder strides
pourrait aussi aider. Un pas est la distance (en octets) qu'il doit parcourir pour passer à la valeur suivante. Pour un tableau 2D, il y aura 2 valeurs de foulée:
In [233]: x=np.arange(12).reshape(3,4).copy()
In [234]: x.strides
Out[234]: (16, 4)
Pour accéder à la ligne suivante, étape 16 octets, colonne suivante uniquement 4.
In [235]: x1.strides
Out[235]: (4, 16)
Transposer change simplement l'ordre des progrès. La rangée suivante n’est que de 4 octets, c’est-à-dire le nombre suivant.
In [236]: x.shape=(12,)
In [237]: x.strides
Out[237]: (4,)
Changer la forme modifie également les foulées - parcourez simplement la mémoire tampon 4 octets à la fois.
In [238]: x2=x1.copy()
In [239]: x2.strides
Out[239]: (12, 4)
Même si x2
ressemble à x1
, il a son propre tampon de données, avec les valeurs dans un ordre différent. La colonne suivante a maintenant 4 octets de plus, tandis que la rangée suivante est 12 (3 * 4).
In [240]: x2.shape=(12,)
In [241]: x2.strides
Out[241]: (4,)
Et comme avec x
, changer la forme en 1d réduit les pas à (4,)
.
Pour x1
, avec les données dans le 0,1,2,...
ordre, il n'y a pas une foulée 1d qui donnerait 0,4,8...
.
__array_interface__
est un autre moyen utile d’afficher des informations sur un tableau:
In [242]: x1.__array_interface__
Out[242]:
{'strides': (4, 16),
'typestr': '<i4',
'shape': (4, 3),
'version': 3,
'data': (163336056, False),
'descr': [('', '<i4')]}
Le x1
l'adresse du tampon de données sera la même que pour x
, avec lequel il partage les données. x2
a une adresse de tampon différente.
Vous pouvez également expérimenter en ajoutant un order='F'
paramètre sur les commandes copy
et reshape
.