ПРИМЕЧАНИЕ: См. Обновление ниже для решения без петель for
.
Это работает для массива любого числа измерений:
def window_argmin(arr):
padded = np.pad(
arr,
[(0,)] * (arr.ndim-1) + [(1,)],
'constant',
constant_values=np.max(arr)+1,
)
slices = np.concatenate(
[
padded[..., np.newaxis, i:i+3]
for i in range(arr.shape[-1])
],
axis=-2,
)
return (
np.argmin(slices, axis=-1) +
np.arange(-1, arr.shape[-1]-1)
)
Код использует np.pad
для дополнения последнего измерения массива дополнительным числом слева и одним справа, поэтому мы всегда можем использовать windows из 3 элементов для argmin. Он устанавливает дополнительные элементы как max + 1, поэтому они никогда не будут выбраны argmin.
Затем он использует np.concatenate
из списка слайсов, чтобы добавить новое измерение с каждым из 3-х элементов * 1046. *. Это единственное место, где мы используем for
l oop, и мы только циклически повторяем последнее измерение, один раз, чтобы создать отдельный 3-элементный windows. (См. Обновление ниже для решения, которое удаляет это for
l oop.)
Наконец, мы вызываем np.argmin
для каждого из windows.
Нам нужно настроить их, что мы можем сделать, добавив смещение первого элемента окна (который на самом деле равен -1 для первого окна, поскольку он является дополненным элементом). Мы можем выполнить корректировку с помощью простой суммы массива arange
, который работает с трансляцией.
Вот тест с вашим образцом массива:
>>> x = np.array([1, 18, 3, 6, 2])
>>> window_argmin(x)
array([0, 0, 2, 4, 4])
И 3D-пример:
>>> z
array([[[ 1, 18, 3, 6, 2],
[ 1, 2, 3, 4, 5],
[ 3, 6, 19, 19, 7]],
[[ 1, 18, 3, 6, 2],
[99, 4, 4, 67, 2],
[ 9, 8, 7, 6, 3]]])
>>> window_argmin(z)
array([[[0, 0, 2, 4, 4],
[0, 0, 1, 2, 3],
[0, 0, 1, 4, 4]],
[[0, 0, 2, 4, 4],
[1, 1, 1, 4, 4],
[1, 2, 3, 4, 4]]])
ОБНОВЛЕНИЕ: Вот версия, использующая stride_tricks , которая не использует петли for
:
def window_argmin(arr):
padded = np.pad(
arr,
[(0,)] * (arr.ndim-1) + [(1,)],
'constant',
constant_values=np.max(arr)+1,
)
slices = np.lib.stride_tricks.as_strided(
padded,
shape=arr.shape + (3,),
strides=padded.strides + (padded.strides[-1],),
)
return (
np.argmin(slices, axis=-1) +
np.arange(-1, arr.shape[-1]-1)
)
Что помогло мне придумать решение трюков шага, было это numpy проблема с просьбой добавить функцию скользящего окна, связанную с примером реализации , поэтому я просто адаптировал ее для этого конкретного c случая. Это все еще в значительной степени волшебные c для меня, но это работает. 10
Протестировано и работает, как ожидается, для массивов разного числа измерений.