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
类的源代码 linked to通过ndarray documentation ,不过C语言就这些了,我不精通,所以理解不了。
然后我注意到有 documentation for ndarray.__getitem__
.我希望这会引导我为类实现 __getitem__
,因为我的理解是实现 __getitem__
是应该定义索引对象的行为的地方。我希望我能够看到他们解压缩元组,然后使用其中包含的切片对象或整数对底层数据结构进行索引,但是这可能需要完成。
那么...让多维切片在 numpy 数组上起作用的幕后究竟发生了什么?
TLDR:如何为 numpy 数组实现多维数组切片?
最佳答案
我们可以用一个简单的类来验证你的第一级推论:
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_
.它们实际上是使用索引语法的类实例。
值得注意的是它是逗号,比创建元组的 ()
更重要:
In [145]: 1,
Out[145]: (1,)
In [146]: 1,2
Out[146]: (1, 2)
In [147]: () # exception - empty tuple, no comma
Out[147]: ()
这解释了语法。但实现细节留给对象类。 list
(以及其他序列,如 string
)可以处理整数和 slice
对象,但在给定元组时会出错。
numpy
对元组很满意。事实上,通过 getitem
传递元组是多年前添加到基础 Python 中的,因为 numpy
需要它。没有基类使用它(据我所知);但用户类可以接受元组,如我的示例所示。
关于numpy
的细节,需要一些numpy
数组存储的知识,包括shape
的作用,strides
和数据缓冲区。我不确定我现在是否想参与其中。
几天前,我探索了一个多维索引示例,发现了一些我没有意识到(或从未见过记录)的细微差别
view of numpy with 2D slicing
对于我们大多数人来说,了解索引的操作方法比了解实现细节更重要。我怀疑有教科书、论文甚至 Wiki 页面都描述了“跨步”多维索引。 numpy
并不是唯一使用它的地方。
https://numpy.org/doc/stable/reference/arrays.indexing.html
这看起来像是对 numpy 数组的一个很好的介绍
https://ajcr.net/stride-guide-part-1/
https://stackoverflow.com/questions/68323196/