Vielleicht hilft dieses Beispiel mit 12 verschiedenen Array-Werten:
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
...
Die C order
Werte sind in der Reihenfolge, in der sie generiert wurden. Die transponierten sind es nicht
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])
Sie können 1d Ansichten von beiden erhalten
In [214]: x1=x.T
In [217]: x.shape=(12,)
Die Form von x
kann auch geändert werden.
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
Die Form der Transponierten kann jedoch nicht geändert werden. Das data
ist immer noch in der 0,1,2,3,4...
Reihenfolge, auf die nicht wie 0,4,8...
in einem 1d-Array zugegriffen werden kann .
Eine Kopie von x1
kann jedoch geändert werden:
In [227]: x2=x1.copy()
In [228]: x2.flags
Out[228]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [229]: x2.shape=(12,)
Ein Blick strides
könnte auch helfen. Ein Schritt ist, wie weit (in Bytes) es gehen muss, um zum nächsten Wert zu gelangen. Für ein 2d-Array gibt es 2 Schrittwerte:
In [233]: x=np.arange(12).reshape(3,4).copy()
In [234]: x.strides
Out[234]: (16, 4)
Um zur nächsten Zeile zu gelangen, Schritt 16 Bytes, nächste Spalte nur 4.
In [235]: x1.strides
Out[235]: (4, 16)
Transponieren ändert nur die Reihenfolge der Schritte. Die nächste Zeile besteht nur aus 4 Bytes, dh der nächsten Nummer.
In [236]: x.shape=(12,)
In [237]: x.strides
Out[237]: (4,)
Durch Ändern der Form werden auch die Schritte geändert. Gehen Sie jeweils 4 Byte durch den Puffer.
In [238]: x2=x1.copy()
In [239]: x2.strides
Out[239]: (12, 4)
Obwohl es so x2
aussieht x1
, hat es einen eigenen Datenpuffer mit den Werten in einer anderen Reihenfolge. Die nächste Spalte ist jetzt 4 Byte länger, während die nächste Zeile 12 (3 * 4) ist.
In [240]: x2.shape=(12,)
In [241]: x2.strides
Out[241]: (4,)
Und wie bei x
reduziert das Ändern der Form auf 1d die Schritte auf (4,)
.
Denn x1
mit Daten in der 0,1,2,...
Reihenfolge gibt es keinen 1d-Schritt, der geben würde 0,4,8...
.
__array_interface__
ist eine weitere nützliche Methode zum Anzeigen von Array-Informationen:
In [242]: x1.__array_interface__
Out[242]:
{'strides': (4, 16),
'typestr': '<i4',
'shape': (4, 3),
'version': 3,
'data': (163336056, False),
'descr': [('', '<i4')]}
Die x1
Datenpufferadresse ist dieselbe wie für x
, mit der die Daten geteilt werden. x2
hat eine andere Pufferadresse.
Sie können auch mit dem Hinzufügen eines order='F'
Parameters zu den Befehlen copy
und experimentieren reshape
.