在多个轴上动态构建切片索引

问题描述 投票:0回答:1

我想从一个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, :]

我很感激任何提示。

python numpy slice
1个回答
0
投票

要创建“动态”索引,您必须首先了解索引本身

最全面的文档页面是

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]])]

研究此类函数的底层代码可能会让您免于“重新发明轮子”。

© www.soinside.com 2019 - 2024. All rights reserved.