为什么将大小为1的维度插入numpy数组会使其“连续”标志无效?

时间:2015-01-29 04:35:18

标签: python numpy

考虑这个数组:

In [1]: a = numpy.array([[1,2],[3,4]], dtype=numpy.uint8)

In [2]: a.strides
Out[2]: (2, 1)

In [3]: a.flat[:]
Out[3]: array([1, 2, 3, 4], dtype=uint8)

In [4]: a.flags['C_CONTIGUOUS']
Out[4]: True

In [5]: numpy.getbuffer(a)[:]
Out[5]: '\x01\x02\x03\x04'

到目前为止,这么好。但是看看当我创建一个该数组的视图时会发生什么,我在其中插入一个大小为1的维度:

In [6]: b = a[:, numpy.newaxis, :] # Insert dimension

In [7]: b.strides
Out[7]: (2, 0, 1)

In [8]: b.flat[:]
Out[8]: array([1, 2, 3, 4], dtype=uint8)

In [9]: b.flags['C_CONTIGUOUS']
Out[9]: False

In [10]: numpy.getbuffer(b)[:]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/.../<ipython-input-28-0127b71fae43> in <module>()
----> 1 numpy.getbuffer(b)[:]

TypeError: single-segment buffer object expected

是什么给出的?为什么numpy认为b不是C_CONTIGUOUS?绝对是,对吗?或者我错过了什么?

更新: @senderle指出numpy.reshape()按预期工作:

In [11]: b = numpy.reshape(a, (2,1,2))

In [12]: b.flags['C_CONTIGUOUS']
Out[12]: True

那很奇怪,我原本以为这两种情况都是一样的。

1 个答案:

答案 0 :(得分:0)

这有点神秘,在我看到hpaulj的评论之前,我甚至挖了一下源代码。他观察reshape并用newaxis切片产生不同的步幅表明了导致这种行为 - 回答问题的原因。

但仍然存在激励这种行为的问题 - 为什么问题。我没有任何可靠的证据证明这一点,但我的直觉是numpy尽其所能快速确保切片是视图,而不是副本,在这种情况下,需要打破c连续性。问题是,可能很难确定如何将正确划分的维度添加到具有奇怪步幅的数组中;在某些情况下甚至可能是不可能的。但是,您始终可以向任何数组添加一个大小为0的维度。因此,numpy只需添加一个步幅0维度,而不是特殊的套管,检查c连续性和其他可能的步幅安排。

这种懒惰是有道理的,因为它更简单,并且(可能)因为它更快(尽管单次检查c邻接不会花费很多时间)。我认为简单解释在这里优先考虑 - 在这种情况下,事情会很快变得非常复杂。

另一方面,

reshape需要能够生成任意形状的数组,因此它尊重邻接要求,并在必须这样做时进行复制。