多维数组slicing/indexing在numpy中是如何实现的?
How is multidimensional array slicing/indexing implemented in numpy?
NumPy 数组的一大特点是可以进行多维切片。我想知道它是如何实现的。让我列出到目前为止我的想法,然后希望有人可以填补空白,回答我的一些问题,并(可能)告诉我为什么我错了。
import numpy as np
arr = np.array([ [1, 2, 3], [4, 5, 6] ])
# retrieve the rightmost column of values for all rows
print(arr[:, 2])
# indexing a normal multidimensional list
not_an_arr = [ [1, 2, 3], [4, 5, 6] ]
print(not_an_arr[:, 2]) # TypeError: indices must be integers or slices, not tuple
起初,[:, 2]
对我来说似乎违反了 Python 语法。如果我试图在 Python 中索引一个普通的多维列表,我会得到一个错误。当然,在实际阅读错误信息后,我意识到问题并不像我最初认为的语法那样,而是传入的对象类型。所以我的结论是结果是 [:, 2]
隐式创建了一个元组,因此 [:, 2]
中真正发生的是 [(:, 2)]
。 是这样吗?
接下来我尝试去阅读numpy.ndarray
class的源码,也就是linked to by the ndarray documentation,不过都是C语言,我不精通,所以可以没看懂这个。
然后我注意到有 documentation for ndarray.__getitem__
。我希望这会引导我为 class 实现 __getitem__
,因为我的理解是实现 __getitem__
是应该定义索引对象的行为的地方。我希望我能够看到他们解压缩元组,然后使用其中包含的切片对象或整数对底层数据结构进行索引,但是这可能需要完成。
那么...让多维切片在 numpy 数组上起作用的幕后究竟发生了什么?
TLDR:如何为numpy数组实现多维数组切片?
我们可以通过简单的 class:
来验证您的第一级推论
In [137]: class Foo():
...: def __getitem__(self,arg):
...: print(arg)
...: return None
...:
In [138]: f=Foo()
In [139]: f[1]
1
In [140]: f[::3]
slice(None, None, 3)
In [141]: f[,]
File "<ipython-input-141-d115e3c638fb>", line 1
f[,]
^
SyntaxError: invalid syntax
In [142]: f[:,]
(slice(None, None, None),)
In [143]: f[:,:3,[1,2,3]]
(slice(None, None, None), slice(None, 3, None), [1, 2, 3])
numpy
在 np.lib.index_tricks.py
中使用这样的代码来实现 np.r_
和 np.s_
等“功能”。它们实际上是 class 个使用索引语法的实例。
值得注意的是逗号,比创建元组的 ()
更重要:
In [145]: 1,
Out[145]: (1,)
In [146]: 1,2
Out[146]: (1, 2)
In [147]: () # exception - empty tuple, no comma
Out[147]: ()
这解释了语法。但是实现细节留给了对象class。 list
(以及 string
等其他序列)可以处理整数和 slice
对象,但在给定元组时会出错。
numpy
对元组很满意。事实上,通过 getitem
传递元组是多年前添加到基础 Python 的,因为 numpy
需要它。没有 base classes 使用它(据我所知);但是用户 classes 可以接受元组,如我的示例所示。
至于numpy
的细节,需要对numpy
数组存储有一定的了解,包括shape
、strides
和data-buffer的作用。我不确定我现在是否想进入这些。
几天前,我探索了一个多维索引示例,发现了一些我没有意识到(或从未见过记录)的细微差别
view of numpy with 2D slicing
对于我们大多数人来说,了解索引的操作方法比了解实现细节更重要。我怀疑有描述 'strided' 多维索引的教科书、论文甚至 Wiki 页面。 numpy
不是唯一使用它的地方。
https://numpy.org/doc/stable/reference/arrays.indexing.html
这看起来像是对 numpy 数组的一个很好的介绍
NumPy 数组的一大特点是可以进行多维切片。我想知道它是如何实现的。让我列出到目前为止我的想法,然后希望有人可以填补空白,回答我的一些问题,并(可能)告诉我为什么我错了。
import numpy as np
arr = np.array([ [1, 2, 3], [4, 5, 6] ])
# retrieve the rightmost column of values for all rows
print(arr[:, 2])
# indexing a normal multidimensional list
not_an_arr = [ [1, 2, 3], [4, 5, 6] ]
print(not_an_arr[:, 2]) # TypeError: indices must be integers or slices, not tuple
起初,[:, 2]
对我来说似乎违反了 Python 语法。如果我试图在 Python 中索引一个普通的多维列表,我会得到一个错误。当然,在实际阅读错误信息后,我意识到问题并不像我最初认为的语法那样,而是传入的对象类型。所以我的结论是结果是 [:, 2]
隐式创建了一个元组,因此 [:, 2]
中真正发生的是 [(:, 2)]
。 是这样吗?
接下来我尝试去阅读numpy.ndarray
class的源码,也就是linked to by the ndarray documentation,不过都是C语言,我不精通,所以可以没看懂这个。
然后我注意到有 documentation for ndarray.__getitem__
。我希望这会引导我为 class 实现 __getitem__
,因为我的理解是实现 __getitem__
是应该定义索引对象的行为的地方。我希望我能够看到他们解压缩元组,然后使用其中包含的切片对象或整数对底层数据结构进行索引,但是这可能需要完成。
那么...让多维切片在 numpy 数组上起作用的幕后究竟发生了什么?
TLDR:如何为numpy数组实现多维数组切片?
我们可以通过简单的 class:
来验证您的第一级推论In [137]: class Foo():
...: def __getitem__(self,arg):
...: print(arg)
...: return None
...:
In [138]: f=Foo()
In [139]: f[1]
1
In [140]: f[::3]
slice(None, None, 3)
In [141]: f[,]
File "<ipython-input-141-d115e3c638fb>", line 1
f[,]
^
SyntaxError: invalid syntax
In [142]: f[:,]
(slice(None, None, None),)
In [143]: f[:,:3,[1,2,3]]
(slice(None, None, None), slice(None, 3, None), [1, 2, 3])
numpy
在 np.lib.index_tricks.py
中使用这样的代码来实现 np.r_
和 np.s_
等“功能”。它们实际上是 class 个使用索引语法的实例。
值得注意的是逗号,比创建元组的 ()
更重要:
In [145]: 1,
Out[145]: (1,)
In [146]: 1,2
Out[146]: (1, 2)
In [147]: () # exception - empty tuple, no comma
Out[147]: ()
这解释了语法。但是实现细节留给了对象class。 list
(以及 string
等其他序列)可以处理整数和 slice
对象,但在给定元组时会出错。
numpy
对元组很满意。事实上,通过 getitem
传递元组是多年前添加到基础 Python 的,因为 numpy
需要它。没有 base classes 使用它(据我所知);但是用户 classes 可以接受元组,如我的示例所示。
至于numpy
的细节,需要对numpy
数组存储有一定的了解,包括shape
、strides
和data-buffer的作用。我不确定我现在是否想进入这些。
几天前,我探索了一个多维索引示例,发现了一些我没有意识到(或从未见过记录)的细微差别
view of numpy with 2D slicing
对于我们大多数人来说,了解索引的操作方法比了解实现细节更重要。我怀疑有描述 'strided' 多维索引的教科书、论文甚至 Wiki 页面。 numpy
不是唯一使用它的地方。
https://numpy.org/doc/stable/reference/arrays.indexing.html
这看起来像是对 numpy 数组的一个很好的介绍