Python 组合索引操作时,视图和副本与NumPy数组混淆

Python 组合索引操作时,视图和副本与NumPy数组混淆,python,arrays,numpy,indexing,copy,Python,Arrays,Numpy,Indexing,Copy,我对python中的视图和副本感到非常困惑。上面的代码显示,第一次将数组a中给定的行和列更改为100时,更改了原始数组a 但是,第二次未更改原始阵列。这是为什么?使用[:,[0,2]]的查找将返回一个副本,因为该副本不可用。但是,当您分配给切片时(例如数组[whatever]=sth),它不会创建副本,而是分配给指定的项目,即使是高级索引 第一个例子之所以有效,是因为第一个切片返回一个视图,然后它对视图的切片使用赋值 但是,第二个“失败”,因为您分配给副本的一个切片(因为高级索引是在常规索引之前

我对python中的视图和副本感到非常困惑。上面的代码显示,第一次将数组a中给定的行和列更改为100时,更改了原始数组a


但是,第二次未更改原始阵列。这是为什么?

使用
[:,[0,2]]
查找将返回一个副本,因为该副本不可用。但是,当您分配给切片时(例如
数组[whatever]=sth
),它不会创建副本,而是分配给指定的项目,即使是高级索引

第一个例子之所以有效,是因为第一个切片返回一个视图,然后它对视图的切片使用赋值

但是,第二个“失败”,因为您分配给副本的一个切片(因为高级索引是在常规索引之前进行的)

区别主要是因为另一个方法负责将()设置为切片,而不是获取()这些切片。要分解您的陈述:

>>> a = np.arange(12).reshape(3,4)

>>> a[0:3:2, :][:, [0,2]] = 100   ### the first time
>>> a  
array([[100, 1, 100, 3],
[ 4, 5, 6, 7],
[100, 9, 100, 11]])

>>> a[:, [0, 2]][0:3:2, :] = 0    ### second time
>>> a   
array([[100, 1, 100, 3],
       [ 4, 5, 6, 7],
       [100, 9, 100, 11]])
第二个是:

a[0:3:2, :][:, [0,2]] = 100 

a.__getitem__((slice(0, 3, 2), slice(None))).__setitem__((slice(None), [0, 2]), 100)
|-------------- returns a view ------------|

使用一组[]进行索引通常更好:
a[0:3:2[0,2]]
。我查找了您上面提供的高级索引链接,但我仍然不确定“[0:3:2,:]”和“[:,[0,2]]”之间有什么区别。对我来说,两者看起来都像元组,为什么一个是高级索引,另一个是常规索引?@BrattSwan第二个轴的
[0,2]
被解释为“整数数组”,这使得NumPy使用整数数组索引(返回副本)。但是
0:3:2
是一个普通的
切片
,所以NumPy使用基本切片(返回一个视图)。真的吗?你得到什么取决于你如何索引它?这太疯狂了!有没有办法强制它只返回一个视图/副本?Thanks@Confounded这并不疯狂——当你得到一个视图(基本索引)和一个副本(高级索引)时,它是完全确定的。因此,如果您总是需要副本,那么只需在返回基本索引时创建一个
.copy()
。但如果不能使用基本切片,则无法通过索引获取视图,因此无法“始终返回视图”。@Confounded Stread表示数组由基本内存地址和跨距(每个维度的步骤)表示。这意味着您可以使用
基本内存地址+(dimension1*strid1+dimension2*strid2…)访问元素
。使用基本切片,您可以简单地返回一个基内存地址已移动且步长已更改的数组。使用高级索引,您可以从数组中获取任意元素,因此不能使用修改的步长,因为可能会有重叠或不连续的步长。因此,实现高级索引的唯一(一致的)方法是:创建新的数组+副本。
a[:, [0,2]][0:3:2, :] = 0

a.__getitem__((slice(None), [0, 2])).__setitem__((slice(0, 3, 2), slice(None)), 0)
|--------- returns a copy ---------|