numpy:复制值默认为整数索引与布尔索引

时间:2014-04-24 10:30:47

标签: python arrays numpy

我最近开始研究McKinney的Python用于数据分析。这让我感到震惊:

  

数组切片是原始数组的视图。这意味着数据不是   复制并对视图的任何修改都将反映在   源数组...由于NumPy已经设计了大数据用例   记住,如果NumPy,你可以想象性能和内存问题   坚持从左到右复制数据。

精细。似乎是一个明智的设计选择。但两页之后它说:

  

通过布尔索引从数组中选择数据始终会创建副本   即使返回的数组没有改变,数据也是如此。

等等,什么?此外,

  

你甚至可以将布尔数组与切片混合搭配......例如data[names == 'Bob', 2:]

现在会有什么回报?对数据副本的看法?为什么这种行为是这样的呢?来自R,我看到布尔索引和基于位置的索引同样经常使用的技术。如果NumPy的设计是为了避免复制内存,那么推动这种设计选择的是什么?

感谢。

2 个答案:

答案 0 :(得分:8)

我们假设一维数组。内存中的数据类似于:

10 | 11 | 12 | 13 | 14 | 15 | 16

按索引访问元素是微不足道的。只需取第一个元素的位置,然后跳转n个步骤。所以,对于arr[2]

10 | 11 | 12 | 13 | 14 | 15 | 16
           ^

我可以通过一次乘法获得内存中的位置。快速而简单。

我可以做一个切片,并说“只采取arr2 = arr[2:-1]”:

10 | 11 | 12 | 13 | 14 | 15 | 16
           ^----^----^----^

现在,内存布局非常相似。获取元素是新起点的倍增。 arr2[1]

10 | 11 | 12 | 13 | 14 | 15 | 16
  (ignore) -----^----------

你可以做一个更高级的技巧,然后说arr3 = arr[::2],让所有元素各跳一次。

10 | 11 | 12 | 13 | 14 | 15 | 16
 ^---------^---------^---------^

再次,获取arr3的索引非常简单:只需进行乘法,但现在大小更大。这就是大步之道,它们会告诉您块的大小以及如何通过索引获取元素。在更多方面,步幅更加强大。顺便说一句,这是我们将内存(1D)转换为矩阵(2D)的方式。

现在,我们开始使用布尔数组。如果我的掩码是:T F T T F F T并且我要求你提供第三个元素,你需要转换掩码,找到第三个是真的,然后得到它的索引;因此,非常慢。因此,当采用布尔掩码时,我们必须复制数据。有一些面具可以用步幅表示,但一般情况下不一样,所以为了保持一致,总是复制。

作为旁注,有时候,制作副本的成本值得表现。如果要执行许多操作读取“数组的每五个元素”,内存中的数据将不会对齐,因此CPU必须等待每次都获取它。然后制作单个副本(将是连续的)并使用它会更快。

答案 1 :(得分:2)

需要一个副本,因为使用任意布尔索引,您无法保证结果可以表示为ndarray。

请参阅:http://scipy-lectures.github.io/advanced/advanced_numpy/#indexing-scheme-strides

以来切片返回视图
  

一切只能通过更改shapestrides以及可能调整data指针来表示!