有没有办法在给定两组角索引坐标的情况下提取任意多维 Python 数组的实心框切片?

Is there a way to extract a solid box slice of an arbitrary multidimensional Python array given two sets of corner index coordinates?

假设我有a = np.arange(16).reshape(4,4),也就是

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

并且想像 a[0:3,1:4] 那样分割 a,结果是

array([[ 1,  2,  3],
       [ 5,  6,  7],
       [ 9, 10, 11]])

使用提供的坐标 [(0,1), (2,3)],它们是该框切片角的索引。

我想创建一个函数,它接受任何 n 维数组和两组索引坐标,并在这两个坐标之间对数组进行切片,包括这两个坐标。 (可能是 Pythonic,我不会包括最后一个索引,所以前面提到的索引坐标将是 [(0,1), (3,4)]。这个细节并不重要。)

一个例子:

import numpy as np

def box_slice(array, start, stop):
    # will return slice
    pass

a = np.arange(3*5*6).reshape(3,5,6)

a现在是

array([[[ 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, 27, 28, 29]],

       [[30, 31, 32, 33, 34, 35],
        [36, 37, 38, 39, 40, 41],
        [42, 43, 44, 45, 46, 47],
        [48, 49, 50, 51, 52, 53],
        [54, 55, 56, 57, 58, 59]],

       [[60, 61, 62, 63, 64, 65],
        [66, 67, 68, 69, 70, 71],
        [72, 73, 74, 75, 76, 77],
        [78, 79, 80, 81, 82, 83],
        [84, 85, 86, 87, 88, 89]]])

这应该等同于 a[0:3, 1:4, 2:5],假设 Pythonic 实现:

box_slice(a, [0,1,2], [3,4,5])

输出:

array([[[ 8,  9, 10],
        [14, 15, 16],
        [20, 21, 22]],

       [[38, 39, 40],
        [44, 45, 46],
        [50, 51, 52]],

       [[68, 69, 70],
        [74, 75, 76],
        [80, 81, 82]]])

这可以通过 eval() 实现,但除非万不得已,否则我不想采用这种方法。是否已经有一个函数可以通过对输入进行最少的操作来实现这一点?我更喜欢使用 NumPy,但也鼓励使用其他库或原始 Python 的解决方案。

解决方案无需修改即可支持任意数量的维度。

我不确定这样做的 numpy 方式,但您可以使用 slicezip 来做到这一点。

import numpy as np

def box_slice(arr, start, stop):
    return arr[tuple(slice(*i) for i in zip(start, stop))]

a = np.arange(16).reshape(4, 4)
print(box_slice(a, [0, 1], [3, 4]))

a = np.arange(3 * 5 * 6).reshape(3, 5, 6)
print(box_slice(a, [0, 1, 2], [3, 4, 5]))

输出

[[ 1  2  3]
 [ 5  6  7]
 [ 9 10 11]]



[[[ 8  9 10]
  [14 15 16]
  [20 21 22]]

 [[38 39 40]
  [44 45 46]
  [50 51 52]]

 [[68 69 70]
  [74 75 76]
  [80 81 82]]]