Python 获取numpy数组的子矩阵何时返回view而不是copy?

Python 获取numpy数组的子矩阵何时返回view而不是copy?,python,arrays,view,numpy,Python,Arrays,View,Numpy,我正在尝试获取numpy 2D数组的子矩阵,并对其进行修改。有时我会得到一个副本,对它的修改不会影响原始阵列: In [650]: d=np.random.rand(5,5) In [651]: may_share_memory(d, d[[0,1],:][:,[2,3]]) Out[651]: False In [652]: d[[0,1],:][:,[2,3]]=2 In [653]: d Out[653]: array([[ 0.0648922 , 0.41408311, 0.

我正在尝试获取numpy 2D数组的子矩阵,并对其进行修改。有时我会得到一个副本,对它的修改不会影响原始阵列:

In [650]: d=np.random.rand(5,5)

In [651]: may_share_memory(d, d[[0,1],:][:,[2,3]])
Out[651]: False

In [652]: d[[0,1],:][:,[2,3]]=2

In [653]: d
Out[653]: 
array([[ 0.0648922 ,  0.41408311,  0.88024646,  0.22471181,  0.81811439],
       [ 0.32154096,  0.88349028,  0.30755883,  0.55301128,  0.61138144],
       [ 0.18398833,  0.40208368,  0.69888324,  0.93197147,  0.43538379],
       [ 0.55633382,  0.80531999,  0.71486132,  0.4186339 ,  0.76487239],
       [ 0.81193408,  0.4951559 ,  0.97713937,  0.33904998,  0.27660239]])
虽然有时我似乎得到了一个视图,但
可能会共享内存
也会返回False

In [662]: d[np.ix_([0,1],[2,3])]=1

In [663]: d
Out[663]: 
array([[ 0.0648922 ,  0.41408311,  1.        ,  1.        ,  0.81811439],
       [ 0.32154096,  0.88349028,  1.        ,  1.        ,  0.61138144],
       [ 0.18398833,  0.40208368,  0.69888324,  0.93197147,  0.43538379],
       [ 0.55633382,  0.80531999,  0.71486132,  0.4186339 ,  0.76487239],
       [ 0.81193408,  0.4951559 ,  0.97713937,  0.33904998,  0.27660239]])

In [664]: may_share_memory(d, d[np.ix_([0,1],[2,3])])
Out[664]: False
更奇怪的是,如果将该“视图”指定给变量,它将成为“副本”(同样,修改不会影响原始数组):


我同意;这很奇怪。但这是有逻辑的

请注意,切片赋值在python中是一种特殊的重载方法。切片分配不会创建视图,然后写入视图;它直接写入数组。无法为[[2,0,1]]的数据数组创建视图,因为无法将此视图表示为跨步数组,而跨步数组是所有numpy函数所需的基本接口。但您可以直接使用索引并对其进行操作。可以说,为了保持一致性,这种切片赋值应该对副本进行修改;但是,如果不将新创建的数组绑定到新名称,那么这又有什么意义呢


在python中,一般来说,赋值和切片赋值是完全不同的野兽,它们做的事情完全不同,这有点尴尬。这也是问题的根源所在。右侧的切片赋值和切片调用不同的函数,在概念上有些不同。may_share_memory指的是右侧切片的行为,而不是切片的作业。

我同意;这很奇怪。但这是有逻辑的

请注意,切片赋值在python中是一种特殊的重载方法。切片分配不会创建视图,然后写入视图;它直接写入数组。无法为[[2,0,1]]的数据数组创建视图,因为无法将此视图表示为跨步数组,而跨步数组是所有numpy函数所需的基本接口。但您可以直接使用索引并对其进行操作。可以说,为了保持一致性,这种切片赋值应该对副本进行修改;但是,如果不将新创建的数组绑定到新名称,那么这又有什么意义呢

在python中,一般来说,赋值和切片赋值是完全不同的野兽,它们做的事情完全不同,这有点尴尬。这也是问题的根源所在。右侧的切片赋值和切片调用不同的函数,在概念上有些不同。may_share_memory指的是右侧切片的行为,而不是切片的作业。

您看到的是

另外,为了清楚起见,
d[np.ix_u([0,1],[2,3])]=1
不是一个视图,而是一个赋值。有关这方面的更多解释,请参见@eelcoogendoorn的答案。您的困惑的根源似乎是Eelco解决的
\uuuuu setitem\uuuuuuuuuuuuuuu
\uuuuuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,但我想我应该添加一些具体的澄清

任何时候你用一系列坐标来索引(
np.ix
返回一个索引数组),它都是“奇特的”索引,并且总是会返回一个副本

使用“始终返回视图”进行切片时可以执行的任何操作

例如:

In [1]: import numpy as np

In [2]: x = np.arange(10)

In [3]: y = x[3:5]

In [4]: z = x[[3, 4]]

In [5]: z[0] = 100

In [5]: x
Out[5]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [6]: y[0] = 100

In [7]: x
Out[7]: array([  0,   1,   2, 100,   4,   5,   6,   7,   8,   9])
原因是numpy数组在内存中必须是半连续的(更准确地说,它们必须能够用偏移量、步长和形状来描述)

任何类型的切片都可以这样描述(甚至像
x[:,3:100:5,无]

不能使用任意坐标序列(例如,
x[[1,4,5100]]

因此,如果使用切片,numpy总是返回一个视图,如果使用“花式索引”(也称为使用一系列标记或布尔掩码)则总是返回一个副本

但是,赋值(例如,
x[blah]=y
)将始终在适当的位置修改numpy数组。

您看到的是

另外,为了清楚起见,
d[np.ix_u([0,1],[2,3])]=1
不是一个视图,而是一个赋值。有关这方面的更多解释,请参见@eelcoogendoorn的答案。您的困惑的根源似乎是Eelco解决的
\uuuuu setitem\uuuuuuuuuuuuuuu
\uuuuuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,但我想我应该添加一些具体的澄清

任何时候你用一系列坐标来索引(
np.ix
返回一个索引数组),它都是“奇特的”索引,并且总是会返回一个副本

使用“始终返回视图”进行切片时可以执行的任何操作

例如:

In [1]: import numpy as np

In [2]: x = np.arange(10)

In [3]: y = x[3:5]

In [4]: z = x[[3, 4]]

In [5]: z[0] = 100

In [5]: x
Out[5]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [6]: y[0] = 100

In [7]: x
Out[7]: array([  0,   1,   2, 100,   4,   5,   6,   7,   8,   9])
原因是numpy数组在内存中必须是半连续的(更准确地说,它们必须能够用偏移量、步长和形状来描述)

任何类型的切片都可以这样描述(甚至像
x[:,3:100:5,无]

不能使用任意坐标序列(例如,
x[[1,4,5100]]

因此,如果使用切片,numpy总是返回一个视图,如果使用“花式索引”(也称为使用一系列标记或布尔掩码)则总是返回一个副本

但是,赋值(例如,
x[blah]=y
)将始终在适当的位置修改numpy数组