a.transpose().ravel()[0]=x 无法更改 numpy 中原始数组的值?
a.transpose().ravel()[0]=x cannot change value of original array in numpy?
环境:Python3.6.0 |Anaconda 自定义(64 位),numpy 版本:1.11.3
示例:
In[1]: import numpy as np
In[2]: a = np.array([[1,2,3], [4,5,6]])
In[3]: a
Out[4]:
array([[1, 2, 3],
[4, 5, 6]])
In[5]: a.transpose()[0] = -1
In[6]: a
Out[6]:
array([[-1, 2, 3],
[-1, 5, 6]])
In[7]: a.ravel()[0] = -2
In[8]: a
Out[8]:
array([[-2, 2, 3],
[-1, 5, 6]])
In[9]: a.transpose().ravel()[0] = -3
In[10]: a
Out[10]:
array([[-2, 2, 3],
[-1, 5, 6]])
我知道transpose()
和ravel()
return一个数组的视图,所以我们可以改变它原来数组的值。但是,当我们使用transpose().ravel()
时,我们不能改变它吗?为什么?
ravel
是 return 复制,而不是视图
A 1-D array, containing the elements of the input, is returned. A copy is made only if needed.
所以基本上,在弄清楚转置时,实际上需要一份副本。您正在更改副本中的值,因此它不会反映在原始数组中。
测试 returned 数组是视图还是副本
对于像这样的简单情况,您可以通过比较 b.base
和 [=21= 的身份来测试数组 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()
return 一份?
令人震惊:实际上有一种方法可以使 a.T.ravel()
return 成为视图而不是副本。您可以通过显式设置 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
中的更改导致视图被 returned,我们可以查看 ravel
函数本身的代码。 np.ndarray.ravel
的实现是 buried in the C layer。阅读源代码,很明显,为了 return 来自 ravel
的视图,必须满足两个条件:
输入数组必须是连续的。
连续输入数组的顺序必须与传入 ravel
的 order
kwarg 的顺序相匹配。
kwarg 的默认值为 order='C'
。因此,默认情况下 ravel
只会 return 如果你 运行 视图在 C 连续数组上。大多数情况下,当您初始化一个新的 Numpy 数组 a
时,它将以 C-contiguous 开始。但是,转置 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 对您来说像是胡言乱语。解释它们需要一个完全不同的问题,很高兴有人已经问过这个问题。这里的 a link to an old answer 给出了 C 和 F 顺序实际含义的真正直观的概述。
警告
在您的实际代码中,我不会太担心 ravel
是 return 次查看还是复制。实际上,您并不总是通过确保使用视图来获得性能提升。通常避免过早优化。
In [382]: a = np.array([[1,2,3], [4,5,6]])
In [383]: a
Out[383]:
array([[1, 2, 3],
[4, 5, 6]])
In [384]: a.ravel()
Out[384]: array([1, 2, 3, 4, 5, 6])
ravel
给出数组的一维视图 - 并按照它们在数据缓冲区中出现的顺序显示值。
In [385]: a.T
Out[385]:
array([[1, 4],
[2, 5],
[3, 6]])
In [386]: a.T.ravel()
Out[386]: array([1, 4, 2, 5, 3, 6])
转置的 ravel
以不同的顺序显示元素 - 除非我们将顺序指定为 'F'(或 'K')。
In [387]: a.T.ravel(order='F')
Out[387]: array([1, 2, 3, 4, 5, 6])
如果数组可以使用原始数据,ravel
(和其他操作)会生成view
,仅在shape
和strides
中发生变化。如果不能,它必须制作一个副本。
由于转置的元素顺序发生变化,使用 [0]
以外的索引进行索引,因此选择了不同的值:
In [397]: a.ravel()[3]
Out[397]: 4 # -1 in your Out[8]
In [398]: a.T.ravel()[3]
Out[398]: 5
当您要求更改转置的第 4 个元素时,您发现存在一定的歧义。它可能会有所不同,具体取决于您遍历元素的方式。
环境:Python3.6.0 |Anaconda 自定义(64 位),numpy 版本:1.11.3
示例:
In[1]: import numpy as np
In[2]: a = np.array([[1,2,3], [4,5,6]])
In[3]: a
Out[4]:
array([[1, 2, 3],
[4, 5, 6]])
In[5]: a.transpose()[0] = -1
In[6]: a
Out[6]:
array([[-1, 2, 3],
[-1, 5, 6]])
In[7]: a.ravel()[0] = -2
In[8]: a
Out[8]:
array([[-2, 2, 3],
[-1, 5, 6]])
In[9]: a.transpose().ravel()[0] = -3
In[10]: a
Out[10]:
array([[-2, 2, 3],
[-1, 5, 6]])
我知道transpose()
和ravel()
return一个数组的视图,所以我们可以改变它原来数组的值。但是,当我们使用transpose().ravel()
时,我们不能改变它吗?为什么?
ravel
是 return 复制,而不是视图
A 1-D array, containing the elements of the input, is returned. A copy is made only if needed.
所以基本上,在弄清楚转置时,实际上需要一份副本。您正在更改副本中的值,因此它不会反映在原始数组中。
测试 returned 数组是视图还是副本
对于像这样的简单情况,您可以通过比较 b.base
和 [=21= 的身份来测试数组 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()
return 一份?
令人震惊:实际上有一种方法可以使 a.T.ravel()
return 成为视图而不是副本。您可以通过显式设置 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
中的更改导致视图被 returned,我们可以查看 ravel
函数本身的代码。 np.ndarray.ravel
的实现是 buried in the C layer。阅读源代码,很明显,为了 return 来自 ravel
的视图,必须满足两个条件:
输入数组必须是连续的。
连续输入数组的顺序必须与传入
ravel
的order
kwarg 的顺序相匹配。
kwarg 的默认值为 order='C'
。因此,默认情况下 ravel
只会 return 如果你 运行 视图在 C 连续数组上。大多数情况下,当您初始化一个新的 Numpy 数组 a
时,它将以 C-contiguous 开始。但是,转置 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 对您来说像是胡言乱语。解释它们需要一个完全不同的问题,很高兴有人已经问过这个问题。这里的 a link to an old answer 给出了 C 和 F 顺序实际含义的真正直观的概述。
警告
在您的实际代码中,我不会太担心 ravel
是 return 次查看还是复制。实际上,您并不总是通过确保使用视图来获得性能提升。通常避免过早优化。
In [382]: a = np.array([[1,2,3], [4,5,6]])
In [383]: a
Out[383]:
array([[1, 2, 3],
[4, 5, 6]])
In [384]: a.ravel()
Out[384]: array([1, 2, 3, 4, 5, 6])
ravel
给出数组的一维视图 - 并按照它们在数据缓冲区中出现的顺序显示值。
In [385]: a.T
Out[385]:
array([[1, 4],
[2, 5],
[3, 6]])
In [386]: a.T.ravel()
Out[386]: array([1, 4, 2, 5, 3, 6])
转置的 ravel
以不同的顺序显示元素 - 除非我们将顺序指定为 'F'(或 'K')。
In [387]: a.T.ravel(order='F')
Out[387]: array([1, 2, 3, 4, 5, 6])
如果数组可以使用原始数据,ravel
(和其他操作)会生成view
,仅在shape
和strides
中发生变化。如果不能,它必须制作一个副本。
由于转置的元素顺序发生变化,使用 [0]
以外的索引进行索引,因此选择了不同的值:
In [397]: a.ravel()[3]
Out[397]: 4 # -1 in your Out[8]
In [398]: a.T.ravel()[3]
Out[398]: 5
当您要求更改转置的第 4 个元素时,您发现存在一定的歧义。它可能会有所不同,具体取决于您遍历元素的方式。