Как построить argsecondmax в Numpy

В Numpy argmax уже определен, но мне нужен argsecondmax, который по сути является вторым максимумом. Как я могу это сделать, я немного запутался?

2 ответа

Решение

обнаружение Nthсамые большие показатели

Эффективный можно использоватьnp.argparition это пропускает сортировку и просто разделение, которое при нарезке даст нам требуемые индексы. Мы также обобщим это, чтобы найти Nth самый большой вдоль указанной оси или глобальный (аналогично ndarray.argmax()), вот так -

def argNmax(a, N, axis=None):
    if axis is None:
        return np.argpartition(a.ravel(), -N)[-N]
    else:
        return np.take(np.argpartition(a, -N, axis=axis), -N, axis=axis)

Образцы прогонов -

In [66]: a
Out[66]: 
array([[908, 770, 258, 534],
       [399, 376, 808, 750],
       [655, 654, 825, 355]])

In [67]: argNmax(a, N=2, axis=0)
Out[67]: array([2, 2, 1, 0])

In [68]: argNmax(a, N=2, axis=1)
Out[68]: array([1, 3, 0])

In [69]: argNmax(a, N=2) # global second largest index
Out[69]: 10

обнаружение Nthнаименьшие показатели

Расширяя это, чтобы найтиNthнаименьший по оси илиглобально, мы бы имели -

def argNmin(a, N, axis=None):
    if axis is None:
        return np.argpartition(a.ravel(), N-1)[N-1]
    else:
        return np.take(np.argpartition(a, N-1, axis=axis), N-1, axis=axis)

Образцы прогонов -

In [105]: a
Out[105]: 
array([[908, 770, 258, 534],
       [399, 376, 808, 750],
       [655, 654, 825, 355]])

In [106]: argNmin(a, N=2, axis=0)
Out[106]: array([2, 2, 1, 0])

In [107]: argNmin(a, N=2, axis=1)
Out[107]: array([3, 0, 1])

In [108]: argNmin(a, N=2)
Out[108]: 11

Задержки

Чтобы дать представление о преимуществах использования argpartitionпо фактической сортировке сargsortкак показано в@pythonic833's postвот быстрый тест времени выполнения на глобальной версии argmax -

In [70]: a = np.random.randint(0,99999,(1000,1000))

In [72]: %timeit np.argsort(a)[-2] # @pythonic833's soln
10 loops, best of 3: 40.6 ms per loop

In [73]: %timeit argNmax(a, N=2)
100 loops, best of 3: 2.12 ms per loop

Ты можешь использовать np.argsort сделать так

test =np.random.randint(1,5,10)

Выход

array([3, 2, 3, 1, 4, 1, 3, 1, 3, 3])

чтобы получить второй максимум, который мы делаем

test[np.argsort(test)[-2]]

np.argsort сортирует в порядке возрастания, поэтому для максимума мы берем последнее значение, для второго максимума - второе последнее.

Изменить: Чтобы улучшить этот ответ, я пишу функцию, аналогичную предоставленной Divakar ( /questions/609192/kak-postroit-argsecondmax-v-numpy/609213#609213).

def argNmax(a, N, axis=None):
    return np.take(np.argsort(a, axis=axis), -N)
Другие вопросы по тегам