Quizás este ejemplo con 12 valores de matriz diferentes ayude:
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
...
Los C order
valores están en el orden en que fueron generados. Los transpuestos no son
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])
Puede obtener vistas 1d de ambos
In [214]: x1=x.T
In [217]: x.shape=(12,)
la forma de x
también se puede cambiar.
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
Pero la forma de la transposición no se puede cambiar. El data
todavía está en el 0,1,2,3,4...
orden, que no se puede acceder accede como 0,4,8...
en una matriz de 1d.
Pero x1
se puede cambiar una copia de :
In [227]: x2=x1.copy()
In [228]: x2.flags
Out[228]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [229]: x2.shape=(12,)
Mirar strides
también podría ayudar. Un paso es qué tan lejos (en bytes) tiene que dar un paso para llegar al siguiente valor. Para una matriz 2d, habrá 2 valores de zancada:
In [233]: x=np.arange(12).reshape(3,4).copy()
In [234]: x.strides
Out[234]: (16, 4)
Para ir a la siguiente fila, paso 16 bytes, la siguiente columna solo 4.
In [235]: x1.strides
Out[235]: (4, 16)
Transpose simplemente cambia el orden de los pasos. La siguiente fila tiene solo 4 bytes, es decir, el siguiente número.
In [236]: x.shape=(12,)
In [237]: x.strides
Out[237]: (4,)
Cambiar la forma también cambia las zancadas, simplemente recorra el búfer 4 bytes a la vez.
In [238]: x2=x1.copy()
In [239]: x2.strides
Out[239]: (12, 4)
Aunque x2
tiene el mismo aspecto x1
, tiene su propio búfer de datos, con los valores en un orden diferente. La siguiente columna ahora tiene 4 bytes más, mientras que la siguiente fila tiene 12 (3 * 4).
In [240]: x2.shape=(12,)
In [241]: x2.strides
Out[241]: (4,)
Y al igual que con x
, cambiar la forma a 1d reduce los pasos a (4,)
.
Porque x1
, con los datos en el 0,1,2,...
orden, no hay un paso de 1d que daría 0,4,8...
.
__array_interface__
es otra forma útil de mostrar información de matriz:
In [242]: x1.__array_interface__
Out[242]:
{'strides': (4, 16),
'typestr': '<i4',
'shape': (4, 3),
'version': 3,
'data': (163336056, False),
'descr': [('', '<i4')]}
La x1
dirección del búfer de datos será la misma que para x
, con el que comparte los datos. x2
tiene una dirección de búfer diferente.
También puede experimentar agregando un order='F'
parámetro a los comandos copy
y reshape
.