考虑这个数组:
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
那很奇怪,我原本以为这两种情况都是一样的。
答案 0 :(得分:0)
这有点神秘,在我看到hpaulj的评论之前,我甚至挖了一下源代码。他观察reshape
并用newaxis
切片产生不同的步幅表明了导致这种行为 - 回答问题的原因。
但仍然存在激励这种行为的问题 - 为什么问题。我没有任何可靠的证据证明这一点,但我的直觉是numpy
尽其所能快速确保切片是视图,而不是副本,在这种情况下,需要打破c连续性。问题是,可能很难确定如何将正确划分的维度添加到具有奇怪步幅的数组中;在某些情况下甚至可能是不可能的。但是,您始终可以向任何数组添加一个大小为0
的维度。因此,numpy
只需添加一个步幅0
维度,而不是特殊的套管,检查c连续性和其他可能的步幅安排。
这种懒惰是有道理的,因为它更简单,并且(可能)因为它更快(尽管单次检查c邻接不会花费很多时间)。我认为简单解释在这里优先考虑 - 在这种情况下,事情会很快变得非常复杂。
另一方面, reshape
需要能够生成任意形状的数组,因此它尊重邻接要求,并在必须这样做时进行复制。