首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Numpy:视图与切片复制

Numpy:视图与切片复制
EN

Stack Overflow用户
提问于 2017-11-08 13:33:26
回答 3查看 11.5K关注 0票数 30

当我进行切片时,发生了一件意外的事情,似乎第一个是视图,而第二个是复制。

第一

首先是行切片,然后是列切片。这似乎是一种看法。

代码语言:javascript
复制
>>> a = np.arange(12).reshape(3, 4)   
>>> a[0:3:2, :][:, [0, 2]] = 100
>>> a
array([[100,   1, 100,   3],
       [  4,   5,   6,   7],
       [100,   9, 100,  11]])

第二

但是,如果我首先切片列,然后切片行,它似乎是一个副本:

代码语言:javascript
复制
>>> a[:, [0, 2]][0:3:2, :] = 0
>>> a
array([[100,   1, 100,   3],
       [  4,   5,   6,   7],
       [100,   9, 100,  11]])

我很困惑,因为这两种方法最终会导致位置的改变,但是为什么第二种方法实际上不改变数字呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-08 14:07:41

重要的是您是按行还是按列进行切片。按行切片可以返回视图,因为它是原始数组的连续段。按列切片必须返回副本,因为它不是连续段。例如:

代码语言:javascript
复制
A1 A2 A3
B1 B2 B3
C1 C2 C3

默认情况下,它以如下方式存储在内存中:

代码语言:javascript
复制
A1 A2 A3 B1 B2 B3 C1 C2 C3

因此,如果要选择第二行,则如下所示:

代码语言:javascript
复制
[A1 A2 A3] B1 B2 B3 [C1 C2 C3]

可以描述为{start: 0, size: 3, stride: 6}

但是,如果您想选择第二列:

代码语言:javascript
复制
[A1] A2 [A3 B1] B2 [B3 C1] C2 [C3]

没有办法用单一的起点、大小和步幅来描述这一点。因此,没有办法建立这样的观点。

如果您希望能够查看每个第二列而不是每一行,则可以用列(主要是Fortran order )来构造数组:

代码语言:javascript
复制
np.array(a, order='F')

然后它将按如下方式存储:

代码语言:javascript
复制
A1 B1 C1 A2 B2 C2 A3 B3 C3
票数 13
EN

Stack Overflow用户

发布于 2019-03-11 16:10:03

约翰·兹温克( John )接受的答案实际上是错误的(我刚想出了一条艰难的道路!)问题中的问题是将“l值索引”与numpy的奇特索引结合起来。下面的文档精确地解释了这个案例

https://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

在“但是花哨的索引有时确实会返回视图”一节中,不是吗?

编辑:

总结上面的链接:

是否创建视图或副本取决于索引是否可以表示为切片。

异常:如果一个人做了“花哨的索引”,那么总是会创建一个副本。花式索引类似于[1,2]。

异常的例外:如果一个人做l值索引(即索引发生在=符号的左边),那么关于创建视图或副本的规则就不再适用了(关于进一步的异常,请参阅下文)。python解释器将直接将值赋值到左侧,而不创建副本或视图。

要证明在这两种情况下都创建了副本,您可以分两个步骤进行操作:

代码语言:javascript
复制
>>> a = np.arange(12).reshape(3, 4)
>>> b = a[0:3:2, :][:, [0, 2]]
>>> b[:] = 100
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

代码语言:javascript
复制
>>> b = a[:, [0, 2]][0:3:2, :]
>>> b[:] = 0
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

顺便说一句,原来的海报上的问题就是上面的食谱链接的末尾所提到的问题。这本书没有给出解决办法。这个问题的棘手之处在于,有两个索引操作是连续完成的。

异常的异常():如果在左侧一行执行两个索引操作(如本问题中的情况),则l值索引中的直接赋值只有在第一个索引操作可以表示为切片时才能工作。否则,即使是l值索引,也必须创建副本。

票数 28
EN

Stack Overflow用户

发布于 2020-12-04 20:44:32

这是我的理解,供你参考

代码语言:javascript
复制
a[0:3:2, :]                     # basic indexing, a view
... = a[0:3:2, :][:, [0, 2]]    # getitme version, a copy,
                                # because you use advanced
                                # indexing [:,[0,2]]
a[0:3:2, :][:, [0, 2]] = ...    # howver setitem version is
                                # like a view, setitem version
                                # is different from getitem version,
                                # this is not c++
a[:, [0, 2]]                    # getitem version, a copy,
                                # because you use advanced indexing
a[:, [0, 2]][0:3:2, :] = 0      # the copy is modied,
                                # but a keeps unchanged.

如果我有什么误会,请指出。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47181092

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档