NumPy предлагает способ получить индекс максимального значения массива через np.argmax
.
Я хотел бы подобное, но возвращая индексы N
максимальных значений.
Например, если у меня есть массив, [1, 3, 2, 4, 5]
, function(array, n=3)
будет возвращать индексы , [4, 3, 1]
которые соответствуют элементам [5, 4, 3]
.
python
numpy
max
numpy-ndarray
Алексис Метеро
источник
источник
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5])
, йотыn= 3
? Какой из всех альтернатив, как[0, 2, 3]
,[0, 2, 9]
,...
будет правильным? Пожалуйста, опишите подробнее ваши конкретные требования. Спасибоargsort
может быть жизнеспособной альтернативой, если вы не заботитесь о порядке возврата. Смотрите мой ответ ниже.Ответы:
Самое простое, что я смог придумать, это:
Это включает в себя полный вид массива. Интересно,
numpy
предоставляет ли встроенный способ сделать частичную сортировку; до сих пор я не смог найти один.Если это решение оказывается слишком медленным (особенно для небольших
n
), возможно, стоит взглянуть на кодирование чего-либо в Cython .источник
arr.argsort()[-1:-4:-1]
? Я пробовал это в интерпретаторе, и это дает тот же результат, но мне интересно, не нарушено ли это каким-то примером.np.argsort(-arr)[:3]
, который я считаю более читабельным и по существу.arr.argsort()[::-1][:n]
лучше, потому что он возвращает пустойn=0
вместо вместо полного массиваБолее новые версии NumPy (1.8 и выше) имеют функцию, вызываемую
argpartition
для этого. Чтобы получить индексы четырех крупнейших элементов, сделайтеВ отличие от
argsort
этого, в худшем случае эта функция выполняется за линейное время, но возвращаемые индексы не сортируются, как видно из результата оценкиa[ind]
. Если вам это тоже нужно, рассортируйте их потом:Таким образом, чтобы получить топ- k элементов в отсортированном порядке, требуется O ( n + k log k ) времени.
источник
argpartition
выполняется за линейное время O (n) с использованием алгоритма интроселекции . Последующая сортировка обрабатывает только k элементов, поэтому выполняется в O (k log k).np.argpartition
и как работает его родственный алгоритм,np.partition
в связанном вопросе есть более подробное объяснение: stackoverflow.com/questions/10337533/…a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
потому что обычные списки Python не поддерживают индексацию по спискам, в отличие отnp.array
np.argpartition
принимает необязательныйaxis
аргумент. Чтобы найти индексы верхних значений n для каждой строки:np.argpartition(a, -n, axis=1)[-n:]
Еще проще:
где n - количество максимальных значений.
источник
arr[arr.argsort()[-n:]]
вместо отрицания массива, просто взять кусочек последних n элементовИспользование:
Для обычных списков Python:
Если вы используете Python 2, используйте
xrange
вместоrange
.Источник: heapq - алгоритм очереди кучи
источник
heapq.nlargest(3, xrange(len(a)), a.take)
. Для списков Python мы можем использовать.__getitem__
вместо.take
.A
в целом:heapq.nlargest(3, range(len(A.ravel())), A.ravel().take)
. (Я надеюсь, что это работает только для представлений, см. Также (ravel vs flatten
] ( stackoverflow.com/a/28930580/603003 )).Если вы работаете с многомерным массивом, вам нужно сгладить и распутать индексы:
Например:
источник
Если вас не интересует порядок K-го по величине элемента, который вы можете использовать
argpartition
, который должен работать лучше, чем полная сортировкаargsort
.Кредиты идут на этот вопрос .
Я провел несколько тестов, и это выглядит
argpartition
лучше,argsort
чем размер массива и значение K увеличивается.источник
Для многомерных массивов вы можете использовать
axis
ключевое слово, чтобы применить разбиение вдоль ожидаемой оси.И для захвата предметов:
Но учтите, что это не вернет отсортированный результат. В этом случае вы можете использовать
np.argsort()
вдоль намеченной оси:Вот пример:
источник
np.take_along_axis
(который, вероятно, не существовал, когда вы ответили на этот вопрос)Это будет быстрее, чем полная сортировка, в зависимости от размера вашего исходного массива и размера вашего выбора:
Это, конечно, включает в себя вмешательство в ваш исходный массив. Что вы можете исправить (если необходимо), сделав копию или заменив исходные значения. ... в зависимости от того, что дешевле для вашего случая использования.
источник
argmax(.)
однозначной. (ИМХО он пытается следовать какой-то логике короткого замыкания, но, к сожалению, не обеспечивает универсально приемлемого поведения). СпасибоМетод
np.argpartition
возвращает только k самых больших индексов, выполняет локальную сортировку и работает быстрее, чемnp.argsort
(при выполнении полной сортировки), когда массив довольно большой. Но возвращенные индексы НЕ находятся в порядке возрастания / убывания . Давайте скажем с примером:Мы можем видеть, что если вы хотите строгие индексы top k в порядке возрастания,
np.argpartition
вы не получите то, что хотите.Помимо выполнения сортировки вручную после np.argpartition, мое решение состоит в том, чтобы использовать PyTorch,
torch.topk
инструмент для построения нейронных сетей, предоставляющий API-интерфейсы, подобные NumPy, с поддержкой как CPU, так и GPU. Это так же быстро, как NumPy с MKL, и предлагает повышение GPU, если вам нужны большие матричные / векторные вычисления.Строгое кодирование индексов восходящих и нисходящих верхних k будет:
Обратите внимание, что
torch.topk
принимает тензор факела и возвращает как верхние значения k, так и верхние k индексы по типуtorch.Tensor
. Как и в случае с np, torch.topk также принимает аргумент оси, так что вы можете обрабатывать многомерные массивы / тензоры.источник
Использование:
Теперь
result
список будет содержать N кортежей (index
,value
), гдеvalue
развернуто.источник
Использование:
Это также работает с 2D массивами. Например,
источник
bottleneck
имеет функцию частичной сортировки, если затраты на сортировку всего массива просто для получения N самых больших значений слишком велики.Я ничего не знаю об этом модуле; Я просто погуглил
numpy partial sort
.источник
Ниже приведен очень простой способ увидеть максимальные элементы и их позиции. Здесь
axis
домен;axis
= 0 означает максимальное число по столбцам, аaxis
= 1 означает максимальное число по строкам для 2D-случая. А для более высоких измерений это зависит от вас.источник
Я нашел это наиболее интуитивно понятным в использовании
np.unique
.Идея состоит в том, что уникальный метод возвращает индексы входных значений. Затем из максимального уникального значения и признаков можно воссоздать положение исходных значений.
источник
Я думаю, что наиболее эффективный способ - это перебирать вручную массив и сохранять минимальную кучу размера k, как уже упоминали другие.
И я также придумала подход грубой силы:
Установите для наибольшего элемента большое отрицательное значение после того, как вы используете argmax для получения его индекса. И тогда следующий вызов argmax вернет второй по величине элемент. И вы можете записать первоначальное значение этих элементов и восстановить их, если хотите.
источник
Этот код работает для матричного массива:
Это приводит к матричной индексации true-false n_largest, которая также работает для извлечения элементов n_largest из матричного массива
источник