ravel 正在返回一个副本,而不是一个视图
来自numpy.ravel docs:
返回一个包含输入元素的一维数组。仅在需要时才制作副本。
因此,基本上,在整理转置时,实际上需要一个副本。您正在更改副本中的值,因此不会反映在原始数组中。
测试返回的数组是视图还是副本
对于这样一个简单的情况,您可以通过比较b.base 和a 的身份来测试数组b 是否是a 的视图:
a = np.array([[1,2,3], [4,5,6]])
b = a.T
c = b.ravel()
print('b is a view of a\n%s\n' % (b.base is a))
print('c is a view of a\n%s\n' % (c.base is a))
输出:
b is a view of a
True
c is a view of a
False
为什么a.T.ravel() 会返回一个副本?
Shocker:实际上有一种方法可以让a.T.ravel() 返回视图而不是副本。你可以通过显式设置order='F'(即Fortran顺序)来做到这一点:
a = np.array([[1,2,3], [4,5,6]])
c = a.T.ravel()
d = a.T.ravel(order='F')
print('d is a view of a\n%s\n' % (d.base is a))
输出:
d is a view of a
True
但是,更改 order kwarg 的值将更改 raveled 数组中值的顺序(花哨的):
print('c\n%s\n' % c)
print('d\n%s\n' % d)
输出:
c
[1 4 2 5 3 6]
d
[1 2 3 4 5 6]
为了理解为什么order 的更改会导致视图被返回,我们可以查看ravel 函数本身的代码。 np.ndarray.ravel 的实现是buried in the C layer。阅读源代码,很明显,为了从ravel 返回视图,必须满足两个条件:
kwarg 的默认值为order='C'。因此,默认情况下,ravel 仅在您在 C 连续数组上运行时才会返回视图。大多数情况下,当您初始化一个新的 Numpy 数组 a 时,它将以 C 连续开始。但是,转置a.T 将是 F 连续的。通过检查数组的.flags property,您可以在代码中看到这一点:
a = np.array([[1,2,3], [4,5,6]])
print('the flags of a\n%s\n' % a.flags)
print('the flags of a.T\n%s\n' % a.T.flags)
输出:
the flags of a
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
the flags of a.T
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : False
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
C 和 F 连续是什么意思?
C-contiguous 和 F-contiguous 术语对您来说很可能是胡言乱语。解释它们需要另一个问题,很高兴有人在 SO 上已经问过了。这是a link to an old answer,它非常直观地概述了 C 和 F 顺序的实际含义。
警告
在您的实际代码中,我不会太担心ravel 是返回视图还是副本。实际上,您并不总是通过确保使用视图来提高性能。一般避免过早优化。