Нарезка массива numpy вдоль динамически заданной оси

Я хотел бы динамически отрезать массив numpy вдоль определенной оси. Учитывая это:

axis = 2
start = 5
end = 10

Я хочу добиться того же результата, что и:

# m is some matrix
m[:,:,5:10]

Используя что-то вроде этого:

slc = tuple(:,) * len(m.shape)
slc[axis] = slice(start,end)
m[slc]

Но значения : не могут быть помещены в кортеж, поэтому я не могу понять, как построить срез.

Ответ 1

Я думаю, что одним из способов было бы использовать slice(None):

>>> m = np.arange(2*3*5).reshape((2,3,5))
>>> axis, start, end = 2, 1, 3
>>> target = m[:, :, 1:3]
>>> target
array([[[ 1,  2],
        [ 6,  7],
        [11, 12]],

       [[16, 17],
        [21, 22],
        [26, 27]]])
>>> slc = [slice(None)] * len(m.shape)
>>> slc[axis] = slice(start, end)
>>> np.allclose(m[slc], target)
True

У меня есть смутное чувство, что раньше я использовал функцию для этого, но теперь я не могу найти его.

Ответ 2

Как было сказано недостаточно ясно (и я тоже искал):

эквивалент:

a = my_array[:, :, :, 8]
b = my_array[:, :, :, 2:7]

является:

a = my_array.take(indices=8, axis=3)
b = my_array.take(indices=range(2, 7), axis=3)

Ответ 3

Это немного поздно для вечеринки, но Numpy по умолчанию делает это numpy.take. Однако тот всегда копирует данные (так как он поддерживает необычную индексацию, он всегда предполагает, что это возможно). Чтобы избежать этого (во многих случаях вам понадобится просмотр данных, а не их копии), воспользуйтесь опцией slice(None), уже упомянутой в другом ответе, возможно, обернув ее в приятную функцию:

def simple_slice(arr, inds, axis):
    # this does the same as np.take() except only supports simple slicing, not
    # advanced indexing, and thus is much faster
    sl = [slice(None)] * arr.ndim
    sl[axis] = inds
    return arr[tuple(sl)]

Ответ 4

Существует элегантный способ доступа к произвольной оси n массива x: используйте numpy.moveaxis ¹, чтобы переместить интересующую ось вперед.

x_move = np.moveaxis(x, n, 0)  # move n-th axis to front
x_move[start:end]              # access n-th axis

Подвох в том, что вам, вероятно, придется применить moveaxis к другим массивам, которые вы используете с выводом x_move[start:end], чтобы сохранить согласованность порядка осей. Массив x_move является только видом, поэтому каждое изменение, которое вы вносите в его переднюю ось, соответствует изменению x на оси n -th (то есть вы можете читать/записывать в x_move).


1) Вы также можете использовать свапы, чтобы не беспокоиться о порядке n и 0, в отличие от moveaxis(x, n, 0). Я предпочитаю moveaxis, чем swapaxes, потому что это только меняет порядок относительно n