Можно ли использовать 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]