Можно ли использовать argsort в порядке убывания?

Рассмотрим следующий код:

avgDists = np.array([1, 8, 6, 9, 4])
ids = avgDists.argsort()[:n]

Это дает мне индексы самых маленьких элементов n. Можно ли использовать этот же argsort в порядке убывания, чтобы получить индексы n старших элементов?

Ответ 1

Если вы отрицаете массив, наименьшие элементы становятся наивысшими элементами и наоборот. Поэтому индексы наивысших элементов n:

(-avgDists).argsort()[:n]

Другой способ рассуждать об этом, как упоминалось в комментариях, заключается в том, чтобы заметить, что большие элементы приходят последним в argsort. Итак, вы можете прочитать из хвоста argsort, чтобы найти n самые высокие элементы:

avgDists.argsort()[::-1][:n]

Оба метода - это O (n log n) во временной сложности, потому что вызов argsort здесь является доминирующим. Но второй подход имеет приятное преимущество: он заменяет отрицание O (n) массива срезом O (1). Если вы работаете с небольшими массивами внутри циклов, вы можете получить некоторую выгоду от того, чтобы избежать этого отрицания, и если вы работаете с огромными массивами, вы можете сэкономить на использовании памяти, потому что отрицание создает копию всего массива.

Обратите внимание, что эти методы не всегда дают эквивалентные результаты: если для argsort запрашивается стабильная реализация сортировки, например. передав аргумент ключевого слова kind='mergesort', тогда первая стратегия сохранит стабильность сортировки, но вторая стратегия нарушит стабильность (т.е. позиции одинаковых элементов будут отменены).

Ответ 2

Как и в Python, [::-1] переворачивает массив, возвращаемый argsort(), а [:n] дает последние n элементов:

>>> avgDists=np.array([1, 8, 6, 9, 4])
>>> n=3
>>> ids = avgDists.argsort()[::-1][:n]
>>> ids
array([3, 1, 2])

Преимущество этого метода в том, что ids представляет собой представление avgDists:

>>> ids.flags
  C_CONTIGUOUS : False
  F_CONTIGUOUS : False
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

("OWNDATA" в значении False указывает, что это представление, а не копия)

Еще один способ сделать это что-то вроде:

(-avgDists).argsort()[:n]

Проблема в том, что это работает так, чтобы создать негатив каждого элемента в массиве:

>>> (-avgDists)
array([-1, -8, -6, -9, -4])

AND создает копию для этого:

>>> (-avgDists_n).flags['OWNDATA']
True

Так что если вы рассчитываете время каждого, даже с этим очень маленьким набором данных:

>>> import timeit
>>> timeit.timeit('(-avgDists).argsort()[:3]', setup="from __main__ import avgDists")
4.2879798610229045
>>> timeit.timeit('avgDists.argsort()[::-1][:3]', setup="from __main__ import avgDists")
2.8372560259886086

Метод просмотра значительно быстрее (и использует 1/2 памяти...)

Ответ 3

Вы можете использовать команды flip numpy.flipud() или numpy.fliplr(), чтобы получить индексы в порядке убывания после сортировки с помощью команды argsort. То, что я обычно делаю.

Ответ 4

Вместо использования np.argsort вы можете использовать np.argpartition - если вам нужны только индексы наименьших/высших n элементов.

Это не требует сортировки всего массива, а только той части, которая вам нужна, но обратите внимание, что "порядок внутри вашего раздела" равен undefined, поэтому, пока он дает правильные индексы, они могут быть неправильно упорядочены:

>>> avgDists = [1, 8, 6, 9, 4]
>>> np.array(avgDists).argpartition(2)[:2]  # indices of lowest 2 items
array([0, 4], dtype=int64)

>>> np.array(avgDists).argpartition(-2)[-2:]  # indices of highest 2 items
array([1, 3], dtype=int64)

Ответ 5

Вы можете создать копию массива, а затем умножить каждый элемент на -1.
В качестве эффекта наибольшие элементы станут самыми маленькими.
Одинаковыми из n наименьших элементов в копии являются n наибольших элементов в оригинале.

Ответ 6

В вашем примере:

avgDists = np.array([1, 8, 6, 9, 4])

Получить индексы n максимальных значений:

ids = np.argpartition(avgDists, -n)[-n:]

Сортировка в порядке убывания:

ids = ids[np.argsort(avgDists[ids])[::-1]]

Получить результаты (для n = 4):

>>> avgDists[ids]
array([9, 8, 6, 4])

Ответ 7

Как намекнул @Kanmani, для более простой интерпретации может использоваться numpy.flip, как numpy.flip ниже:

import numpy as np

avgDists = np.array([1, 8, 6, 9, 4])
ids = np.flip(np.argsort(avgDists))
print(ids)

Используя шаблон посетителя, а не функции-члены, легче читать порядок операций.

Ответ 8

Другим способом является использование в аргументе argsort только "-": "df [np.argsort(-df [:, 0])]", если df - это кадр данных, и вы хотите его отсортировать по первому столбцу (представленному номером столбца "0" ). При необходимости измените имя столбца. Конечно, столбец должен быть числовым.

Ответ 9

Простой способ - взять абсолютные значения и добавить отрицательный знак к каждому элементу, а затем выполнить argsort.

l=np.array([1,-1,2])
print(np.argsort((-np.abs(x))))  #[2,1,0]