scipy numpy数组切片中出现意外结果(查看与复制)

yvgpqqbh  于 2022-12-13  发布在  其他
关注(0)|答案(3)|浏览(134)

我试图减少代码中的复制量,但在处理numpy数组切片和视图时,我遇到了令人惊讶的行为,如中所述:
复制numpy数组的Scipy wiki页面
我偶然发现了以下行为,这对我来说是意料之外的:

案例1:

import numpy as np
a = np.ones((3,3))
b = a[:,1:2]
b += 5
print a
print b.base is a

正如预期的那样,这将输出:

array([[ 1.,  6.,  1.],
       [ 1.,  6.,  1.],
       [ 1.,  6.,  1.]])
True

**案例2:**在一行中执行切片和加法时,情况会有所不同:

import numpy as np
a = np.ones((3,3))
b = a[:,1:2] + 5
print a
print b.base is a

让我感到惊讶的是,[:,1:2]似乎并不创建视图,它随后被用作左手参数,因此,它输出:

array([[ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 1.,  1.,  1.]])
False

也许有人能解释一下为什么这两个案子不一样,我想我遗漏了什么。

解决方案:我忽略了一个明显的事实,即“+”操作符,而不是就地操作符“+=”,将总是创建一个副本,所以它实际上是无关的,但切片,而不是就地操作符是如何定义的numpy数组。

为了说明这一点,下面的代码生成的输出与第2种情况相同:

import numpy as np
a = np.ones((3,3))
b = a[:,1:2]
b = b + 5
print a
print b.base is a
smtd7mpg

smtd7mpg1#

上述情况无异于:

>>> a=np.arange(5)
>>> b=a
>>> b
array([0, 1, 2, 3, 4])

>>> b+=5
>>> a
array([5, 6, 7, 8, 9])
>>> b
array([5, 6, 7, 8, 9])

>>> b=b+5
>>> b
array([10, 11, 12, 13, 14])
>>> a
array([5, 6, 7, 8, 9])

至少在我看来,这是完全意料之中的行为。b+=x操作符调用__iadd__,它首先尝试在适当的位置修改数组,所以它将 * 更新 * b,它仍然是a的视图。而b=b+x操作符调用__add__,它创建新的临时数据,然后 * 分配 * 给b
对于a[i] +=b,序列为(单位为numpy):

a.__setitem__(i, a.__getitem__(i).__iadd__(b))
9njqaruj

9njqaruj2#

a[:, 1:2]创建了一个视图,但在第二个示例中,您没有修改视图,而是从其参数创建了一个新数组。

a = np.ones((3, 3))
b = a + 5

在这种情况下,您不会期望a发生变化,因为这不是就地加法。运算符是+,而不是+=。第二个示例也是如此。

b = a[:, 1:2] + 5

不会修改a[:, 1:2],因为这不是就地加法。

fwzugrvs

fwzugrvs3#

当对numpy数组进行切片时,默认的做法是创建B作为a的视图,因此当你改变b时,a也会改变,这在第一个案例中得到了证实。
第二种情况更复杂,你不是说B是a的一个切片,然后加上一个数字,你所做的是创建b作为与a不一致的东西,所以numpy被迫复制数据,而不仅仅是创建一个视图。

相关问题