Forse questo esempio con 12 diversi valori di array aiuterà:
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
...
I C ordervalori sono nell'ordine in cui sono stati generati. Quelli trasposti non lo sono
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])
Puoi ottenere 1d visualizzazioni di entrambi
In [214]: x1=x.T
In [217]: x.shape=(12,)
anche la forma xpuò essere modificata.
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
Ma la forma della trasposizione non può essere modificata. Il dataè ancora in 0,1,2,3,4...ordine, che non può essere letta accessibile come 0,4,8...in un array 1D.
Ma una copia di x1può essere modificata:
In [227]: x2=x1.copy()
In [228]: x2.flags
Out[228]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [229]: x2.shape=(12,)
Anche guardare stridespotrebbe aiutare. Un passo è quanto lontano (in byte) deve fare un passo per arrivare al valore successivo. Per un array 2d, ci saranno 2 valori di stride:
In [233]: x=np.arange(12).reshape(3,4).copy()
In [234]: x.strides
Out[234]: (16, 4)
Per arrivare alla riga successiva, passo 16 byte, colonna successiva solo 4.
In [235]: x1.strides
Out[235]: (4, 16)
Transpose cambia semplicemente l'ordine dei passi. La riga successiva è di soli 4 byte, ovvero il numero successivo.
In [236]: x.shape=(12,)
In [237]: x.strides
Out[237]: (4,)
Cambiare la forma cambia anche i passi: basta scorrere il buffer di 4 byte alla volta.
In [238]: x2=x1.copy()
In [239]: x2.strides
Out[239]: (12, 4)
Anche se x2sembra proprio come x1, ha un proprio buffer di dati, con i valori in un ordine diverso. La colonna successiva è ora di 4 byte, mentre la riga successiva è 12 (3 * 4).
In [240]: x2.shape=(12,)
In [241]: x2.strides
Out[241]: (4,)
E come con x, cambiare la forma in 1d riduce i passi a (4,).
Poiché x1, con i dati 0,1,2,...nell'ordine, non c'è un passo 1d che darebbe 0,4,8....
__array_interface__ è un altro modo utile per visualizzare le informazioni sull'array:
In [242]: x1.__array_interface__
Out[242]:
{'strides': (4, 16),
'typestr': '<i4',
'shape': (4, 3),
'version': 3,
'data': (163336056, False),
'descr': [('', '<i4')]}
L' x1indirizzo del buffer dei dati sarà lo stesso di x, con cui condivide i dati. x2ha un indirizzo di buffer diverso.
Puoi anche provare ad aggiungere un order='F'parametro ai comandi copye reshape.