python - a.transpose().ravel()[0]=x 无法更改 numpy 中原始数组的值?

标签 python numpy deep-copy

环境:Python 3.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()返回数组的 View ,所以我们可以改变它的原始数组的值。但是,当我们使用transpose().ravel()时,我们不能改变它吗?为什么?

最佳答案

ravel 返回的是副本,而不是 View

来自numpy.ravel docs :

A 1-D array, containing the elements of the input, is returned. A copy is made only if needed.

所以基本上,在解开转置时,实际上需要一个副本。您正在更改副本中的值,因此这不会反射(reflect)在原始数组中。

测试返回的数组是 View 还是副本

对于像这样的简单情况,您可以通过比较 b.base 的标识来测试数组 b 是否是 a 的 View 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()返回一个副本?

令人震惊:实际上有一种方法可以使 a.T.ravel() 返回 View 而不是副本。您可以通过显式设置 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 的变化会导致 View 被返回,我们可以查看 ravel 函数本身的代码。 np.ndarray.ravel 的实现是 buried in the C layer 。阅读源代码,很明显,为了从 ravel 返回 View ,必须满足两个条件:

  • 输入数组必须是连续的。

  • 连续输入数组的顺序必须与传递到 ravelorder kwarg 的顺序相匹配。

kwarg 的默认值为 order='C'。因此,默认情况下,如果您在 C 连续数组上运行ravel,它只会返回一个 View 。大多数情况下,当您初始化一个新的 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-连续”和“F-连续”对您来说似乎是胡言乱语。解释它们需要一个完全不同的问题,很高兴有人已经问过这个问题。这是a link to an old answer这非常直观地概述了 C 和 F 顺序的实际含义。

警告

在您的实际代码中,我不会太担心 ravel 是返回 View 还是副本。实际上,通过确保使用 View 并不总能获得性能提升。一般来说,避免过早优化。

关于python - a.transpose().ravel()[0]=x 无法更改 numpy 中原始数组的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54166169/

相关文章:

python - peewee 原始查询不适用于WITH 语句

python - 显式类型的 Python 版本?

python - .apply() 双变量 numpy() lambda 函数到 pandas DataFrame 的 .expanding() 窗口

numpy - 阅读旧的 Numarray 教程和示例需要注意什么?

python - 预处理后将多目录图像保存在单个文件中

python - 为什么我在尝试通过 python 插入数据 MongoDB 时遇到错误?

python - 无法获得具有亮点的图像的准确阈值

javascript - 检测复杂对象的变化

c++ - 如何将指针复制到不完整类型 - C++

javascript - 没有某些字段的深度克隆