也许这个包含 12 个不同数组值的示例会有所帮助:
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
...
C order 值按照它们生成的顺序排列。转置的不是
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])
您可以获得两者的一维视图
In [214]: x1=x.T
In [217]: x.shape=(12,)
x的形状也可以改变。
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
但是转置的形状不能改变。 data 仍处于0,1,2,3,4... 顺序中,无法在一维数组中作为0,4,8... 访问。
但x1 的副本可以更改:
In [227]: x2=x1.copy()
In [228]: x2.flags
Out[228]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
...
In [229]: x2.shape=(12,)
查看strides 也可能有所帮助。步幅是它必须走多远(以字节为单位)才能到达下一个值。对于二维数组,将有 2 个步幅值:
In [233]: x=np.arange(12).reshape(3,4).copy()
In [234]: x.strides
Out[234]: (16, 4)
要到达下一行,步长 16 个字节,下一列只有 4 个。
In [235]: x1.strides
Out[235]: (4, 16)
Transpose 只是切换步幅的顺序。下一行只有 4 个字节——即下一个数字。
In [236]: x.shape=(12,)
In [237]: x.strides
Out[237]: (4,)
改变形状也会改变步幅 - 一次只需 4 个字节的缓冲区。
In [238]: x2=x1.copy()
In [239]: x2.strides
Out[239]: (12, 4)
尽管x2 看起来就像x1,但它有自己的数据缓冲区,并且值的顺序不同。下一列现在超过 4 个字节,而下一行是 12 (3*4)。
In [240]: x2.shape=(12,)
In [241]: x2.strides
Out[241]: (4,)
与x 一样,将形状更改为1d 会将步幅减少到(4,)。
对于x1,使用0,1,2,... 顺序中的数据,没有一维步幅可以提供0,4,8...。
__array_interface__ 是另一种显示数组信息的有用方式:
In [242]: x1.__array_interface__
Out[242]:
{'strides': (4, 16),
'typestr': '<i4',
'shape': (4, 3),
'version': 3,
'data': (163336056, False),
'descr': [('', '<i4')]}
x1 数据缓冲区地址将与 x 相同,并与之共享数据。 x2 有不同的缓冲区地址。
您还可以尝试将order='F' 参数添加到copy 和reshape 命令。