Якщо ви заперечуєте масив, найнижчі елементи стають найвищими елементами і навпаки. Тому індексами n
найвищих елементів є:
(-avgDists).argsort()[:n]
Ще один спосіб аргументувати це, як згадувалося в коментарях , - спостерігати, що великі елементи стають останніми в арґорті. Отже, ви можете прочитати з хвоста аргсорту, щоб знайтиn
найвищі елементи:
avgDists.argsort()[::-1][:n]
Обидва способи є O (n log n) за часовою складністю, оскільки argsort
виклик є домінуючим терміном тут. Але другий підхід має приємну перевагу: він замінює O (n) заперечення масиву на зріз O (1) . Якщо ви працюєте з невеликими масивами всередині циклів, то, можливо, ви отримаєте певну прибутковість від уникнення цього заперечення, а якщо ви працюєте з величезними масивами, ви можете заощадити на використанні пам'яті, оскільки заперечення створює копію всього масиву.
Зауважте, що ці методи не завжди дають еквівалентні результати: якщо вимагається стабільна реалізація сортування argsort
, наприклад, передаючи аргумент ключового слова kind='mergesort'
, тоді перша стратегія збереже стабільність сортування, а друга стратегія порушить стабільність (тобто позиції рівні елементи будуть повернені).
Приклад часу:
Використовуючи невеликий масив із 100 поплавців та довжиною хвоста 30, метод перегляду був на 15% швидшим
>>> avgDists = np.random.rand(100)
>>> n = 30
>>> timeit (-avgDists).argsort()[:n]
1.93 µs ± 6.68 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
1.64 µs ± 3.39 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
1.64 µs ± 3.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Для великих масивів домінуючий арґсорт є суттєвою різницею в часі
>>> avgDists = np.random.rand(1000)
>>> n = 300
>>> timeit (-avgDists).argsort()[:n]
21.9 µs ± 51.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[::-1][:n]
21.7 µs ± 33.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> timeit avgDists.argsort()[-n:][::-1]
21.9 µs ± 37.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Зауважте, що коментар від Nedim нижче невірний. Чи слід усікати до або після реверсування, це не суттєво впливає на ефективність, оскільки обидві ці операції лише по-різному переглядають вид масиву, а фактично не копіюють дані.
ids = np.array(avgDists).argsort()[-n:]
?