优雅的方式来获取NumPy矩阵的多个2D切片?

yws3nbqq  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(143)

假设我有一个非常大的2D矩阵:

import numpy as np

X = np.random.random((8000, 8000))

我有四个非常大的数组(大约500万个元素),它们都有相同的形状,它们是from_rowto_rowfrom_colto_col。这四个数组,顾名思义,代表我想从X矩阵中裁剪的矩形的坐标。生成的矩形保证都有相同的大小。
基本上,我想以更有效的方式做这样的事情:

n_rects = len(from_row)  # The four arrays have the same shape
crops = np.zeros((n_rects, rect_height, rect_width), dtype=X.dtype)
for i in range(n_rects):
    crop[i] = X[from_row[i]:to_row[i], from_col[i]:to_col[i]]

有没有可能更有效地做这样的事情?

pprl5pva

pprl5pva1#

编辑:另一种更简单的方法是索引数组的滑动窗口视图:

from numpy.lib.stride_tricks import sliding_window_view as swv
out = swv(X, (rect_height, rect_width))[from_row, from_col]

为了方便起见,您可以利用numpy的高级索引规则与广播相结合,以矢量化的方式实现这一点。请注意,为了使其工作,每个矩形都需要具有相同的大小,因此使用startsize而不是startend可能更自然。下面是一个示例:

import numpy as np

H, W = 10, 10
X = np.arange(H * W).reshape(H, W)

n_rects = 5
rect_height, rect_width = 4, 6

# Some random starting indices
from_row = np.random.randint(H - rect_height, size=n_rects)
from_col = np.random.randint(W - rect_width, size=n_rects)

# Numpy magic:
rows = from_row[:, None, None] + np.arange(rect_height)[None, :, None]
cols = from_col[:, None, None] + np.arange(rect_width)[None, None, :]
# Note that `rows` and `cols` broadcast to a
# shape `(n_rects, rect_height, rect_width)` array

# Now simply index:
out = X[rows, cols]

结果:

>>> from_row
array([5, 4, 3, 3, 4])
>>> from_col
array([2, 3, 1, 0, 1])
>>> out
array([[[52, 53, 54, 55, 56, 57],
        [62, 63, 64, 65, 66, 67],
        [72, 73, 74, 75, 76, 77],
        [82, 83, 84, 85, 86, 87]],

       [[43, 44, 45, 46, 47, 48],
        [53, 54, 55, 56, 57, 58],
        [63, 64, 65, 66, 67, 68],
        [73, 74, 75, 76, 77, 78]],

       [[31, 32, 33, 34, 35, 36],
        [41, 42, 43, 44, 45, 46],
        [51, 52, 53, 54, 55, 56],
        [61, 62, 63, 64, 65, 66]],

       [[30, 31, 32, 33, 34, 35],
        [40, 41, 42, 43, 44, 45],
        [50, 51, 52, 53, 54, 55],
        [60, 61, 62, 63, 64, 65]],

       [[41, 42, 43, 44, 45, 46],
        [51, 52, 53, 54, 55, 56],
        [61, 62, 63, 64, 65, 66],
        [71, 72, 73, 74, 75, 76]]])

相关问题