我想从一个n维数组中提取一个切片。每个轴的切片索引是动态计算的,并且是 None (=所有索引)或任何有序或无序序列。因此我认为为每个轴使用切片对象是一个合理的选择。此外,我先验不知道n维数组的轴数。并且结果必须是索引指令给出的形状。
a = np.arange(10*8).reshape((10, 8))
slc = [slice(None)] * a.ndim
slc[0] = np.arange(3, 8)
slc[1] = np.arange(2, 4)
a[tuple(slc)]
此示例片段应该演示用法。仅对一个轴使用一个切片对象效果很好。但是同时使用两个切片对象会失败。
编辑1:
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (5,) (2,)
编辑2:这解决了问题
slc[0] = np.arange(3, 8)[:, None]
slc[1] = np.arange(2, 4)[None, :]
我很感激任何提示。
要创建“动态”索引,您必须首先了解索引本身
最全面的文档页面是
https://numpy.org/doc/stable/user/basics.indexing.html
它还链接到索引例程页面
https://numpy.org/doc/stable/reference/arrays.indexing.html#routines-indexing
你的基本二维数组
In [183]: a = np.arange(10*8).reshape((10, 8))
使用切片元组可以
basic indexing
,这里 5 行,2 列:
In [184]: a[3:8, 2:4]
Out[184]:
array([[26, 27],
[34, 35],
[42, 43],
[50, 51],
[58, 59]])
您可以使用
slice
对象列表来执行相同操作:
In [185]: idx = [slice(3,8), slice(2,4)]; a[tuple(idx)]
Out[185]:
array([[26, 27],
[34, 35],
[42, 43],
[50, 51],
[58, 59]])
您的第一个错误是您尝试使用数组来进行索引,而不是
slice
对象。 (好的,您用 slice(None)
初始化了列表,但用数组替换了所有元素。)
In [186]: slc = [np.arange(3,8), np.arange(2,4)]
In [187]: a[tuple(slc)]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[187], line 1
----> 1 a[tuple(slc)]
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (5,) (2,)
如果不了解 numpy,你就无法做到
advanced indexing
broadcasting
:
In [188]: a[slc[0][:,None], slc[1]]
Out[188]:
array([[26, 27],
[34, 35],
[42, 43],
[50, 51],
[58, 59]])
您可以使用多个一维数组,但它们必须匹配,也就是说,它们必须
broadcast
。结果是 1d,与这些数组匹配。我认为这是取块的“对角线”:
In [190]: a[slc[0],slc[0]]
Out[190]: array([27, 36, 45, 54, 63])
索引块和索引“对角线”之间的区别似乎让任性的 MATLAB 程序员感到困惑,因为符号几乎完全相反。
制作可广播数组的一个方便工具是
np.ix_
:
In [191]: np.ix_(*slc)
Out[191]:
(array([[3],
[4],
[5],
[6],
[7]]),
array([[2, 3]]))
In [192]: a[np.ix_(*slc)]
Out[192]:
array([[26, 27],
[34, 35],
[42, 43],
[50, 51],
[58, 59]])
此函数/类和其他函数/类列在
indexing routines
页面中。许多都在 np.lib.indexing_tricks.py
文件中定义。
这是一个将切片表示法转换为范围并连接的类实例:
In [193]: np.r_[3:8, 2:4]
Out[193]: array([3, 4, 5, 6, 7, 2, 3])
第一个将切片符号转换为切片对象的元组:
In [194]: np.s_[3:8, 2:4]
Out[194]: (slice(3, 8, None), slice(2, 4, None))
另一个将切片扩展为数组的类实例:
In [195]: np.ogrid[3:8, 2:4]
Out[195]:
[array([[3],
[4],
[5],
[6],
[7]]),
array([[2, 3]])]
还有一个常见的
meshgrid
,可以制作类似的列表:
In [196]: np.meshgrid(*slc, sparse=True, indexing='ij')
Out[196]:
[array([[3],
[4],
[5],
[6],
[7]]),
array([[2, 3]])]
研究此类函数的底层代码可能会让您免于“重新发明轮子”。