numpy argmin векторизация - PullRequest
       0

numpy argmin векторизация

1 голос
/ 21 февраля 2020

Я пытаюсь перебрать по numpy строкам и поместить индекс каждого кластера из 3 элементов, который содержит наименьшее значение, в другую строку. Это должно быть в контексте слева, посередине, справа; левый и правый края смотрят только на два значения («левый и средний» или «средний и правый»), но все в середине должно выглядеть на все 3.

Для циклов это можно сделать тривиально, но это очень медленный. Некоторая разновидность numpy векторизации, вероятно, ускорит это.

Например:

 [1 18 3 6 2]
 # should give the indices...
 [0 0 2 4 4] # matching values 1 1 3 2 2

Медленно для l oop реализации:

for y in range(height):
    for x in range(width):
        i = 0 if x == 0 else x - 1
        other_array[y,x] = np.argmin(array[y,i:x+2]) + i

Ответы [ 2 ]

1 голос
/ 21 февраля 2020

ПРИМЕЧАНИЕ: См. Обновление ниже для решения без петель 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

Протестировано и работает, как ожидается, для массивов разного числа измерений.

0 голосов
/ 21 февраля 2020
import numpy as np
array = [1, 18, 3, 6, 2]
array.insert(0, np.max(array) + 1)     # right shift of array
# [19, 1, 18, 3, 6, 2]

other_array = [ np.argmin(array[i-1:i+2]) + i - 2 for i in range(1, len(array)) ]

array.remove(np.max(array))            # original array
# [1, 18, 3, 6, 2]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...