在advanced indexing的NumPy文档中,提到
Also recognize that
x[[1, 2, 3]]
will trigger advanced indexing, whereasx[[1, 2, slice(None)]]
will trigger basic slicing.
矩阵按顺序存储在存储器中。我知道查看x[[1, 2, slice(None)]]
是有意义的,因为元素是按顺序存储在内存中的。但是为什么Numpy返回x[[1, slice(None), 2]]
或x[[slice(None), 1, 2]]
的视图呢。例如,假设
x = [[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]]]
x[[1, slice(None), 2]]
返回未顺序存储在内存中的[11, 14, 17]
视图,以及返回[5, 14, 23]
的x[[slice(None), 1, 2]]
视图。你知道吗
我想知道
为什么在这两种情况下NumPy甚至返回一个视图
NumPy如何处理内存寻址来创建这些视图
从SciPy cookbook:
当你有一个像
x[[1, slice(None), 2]]
这样的索引时,你会得到一个视图,因为切片整个轴允许一定的偏移、跨距和计数来表示原始数组的切片。你知道吗例如,对于
x = np.arange(27).reshape(3, 3, 3).copy()
,我们有:然后我们可以使用^{} (不是公共API的一部分,YMMV)来说明从原始数组获取切片的偏移量。你知道吗
这是有意义的,因为在片中的第一个值11之前有11个8字节整数。NumPy使用一个公式来计算这个偏移量,这个公式可以see here,使用原始数组的步长。你知道吗
我们切片中的步幅只是成为沿着我们切片的轴的
x
的步幅。i、 例如x.strides[1] == x_view.strides[0]
。现在,偏移量、新的步长和计数加在一起就足够让NumPy从原始数组中查看切片了。你知道吗最后,使用
x[[0, 1, 2]]
触发花哨索引的原因是,在没有全轴切片的情况下,通常不可能制定一些新的偏移量、字节顺序、跨距和计数,以便我们可以使用相同的基础数据查看切片。你知道吗我喜欢使用
__array_interface__
来检查数组的属性:用你的
x
:这是一个(3,3,3)数组。最后一个轴可以一次扫描8个字节,大小为
x.itemsize
。3*8步行,3*3*8步穿过平面(第一个尺寸)。你知道吗y
元素可以通过平面3*3*8步进来寻址。43241832是起点,40字节进入数据缓冲区,5*8所以它从第5个元素开始,一次前进一个平面(9个元素),总共3个元素。你知道吗
y.__array_interface__['data']
在x
“data”范围内的事实告诉我y
是一个视图。这是一个视图,因为这个缓冲区起点、跨步和形状的组合允许我们访问y
的所有值。你知道吗使用高级索引,通常不可能用这些简单的参数访问元素,因此
numpy
必须复制数据。你知道吗只需改变步幅和“数据”起点,就可以得到相反的观点:
转置也会改变步伐:
相关问题 更多 >
编程相关推荐