Пустотливий аргсорт - що це робить?


123

Чому немічний дає такий результат:

x = numpy.array([1.48,1.41,0.0,0.1])
print x.argsort()

>[2 3 1 0]

коли я очікував би це зробити:

[3 2 0 1]

Очевидно, що моє розуміння функції не вистачає.


6
Чому ви думали, [3 2 0 1]що це буде правильна відповідь?
zwol

9
У мене просто було перевернуте розуміння результату. Тобто, якщо ви берете перший елемент x, він повинен знаходитися в положенні 3 відсортованого масиву тощо.
користувач1276273

26
ваш спосіб мислення абсолютно має сенс, у мене було саме те питання
adrienlucca.wordpress.com

2
[3 2 0 1] - це ранжування значень, фактичні показники ви не отримуєте.
Lahiru Karunaratne

Просто пам’ятайте, що висновок вказує місця у вихідному масиві, тоді як ви вважаєте це в відсортованому масиві. Це означає, що вихід [0] є індексом, де найменший елемент в початковому вхідному масиві знаходить і виводить [-1] для найбільшого елемента.
lincr

Відповіді:


143

Відповідно до документації

Повертає індекси, які б сортували масив.

  • 2є індексом 0.0.
  • 3є індексом 0.1.
  • 1є індексом 1.41.
  • 0є індексом 1.48.

12
a = x.argsort(), друк x[a], ми отримаємоarray([ 0. , 0.1 , 1.41, 1.48])
Белтер

39

[2, 3, 1, 0] означає, що найменший елемент знаходиться в індексі 2, наступний найменший в індексі 3, потім індекс 1, потім індекс 0.

Існує кілька способів отримати результат, який ви шукаєте:

import numpy as np
import scipy.stats as stats

def using_indexed_assignment(x):
    "https://stackoverflow.com/a/5284703/190597 (Sven Marnach)"
    result = np.empty(len(x), dtype=int)
    temp = x.argsort()
    result[temp] = np.arange(len(x))
    return result

def using_rankdata(x):
    return stats.rankdata(x)-1

def using_argsort_twice(x):
    "https://stackoverflow.com/a/6266510/190597 (k.rooijers)"
    return np.argsort(np.argsort(x))

def using_digitize(x):
    unique_vals, index = np.unique(x, return_inverse=True)
    return np.digitize(x, bins=unique_vals) - 1

Наприклад,

In [72]: x = np.array([1.48,1.41,0.0,0.1])

In [73]: using_indexed_assignment(x)
Out[73]: array([3, 2, 0, 1])

Це перевіряє, чи всі вони дають однаковий результат:

x = np.random.random(10**5)
expected = using_indexed_assignment(x)
for func in (using_argsort_twice, using_digitize, using_rankdata):
    assert np.allclose(expected, func(x))

Ці %timeitорієнтири IPython передбачають, що для великих масивів using_indexed_assignmentнайшвидший:

In [50]: x = np.random.random(10**5)
In [66]: %timeit using_indexed_assignment(x)
100 loops, best of 3: 9.32 ms per loop

In [70]: %timeit using_rankdata(x)
100 loops, best of 3: 10.6 ms per loop

In [56]: %timeit using_argsort_twice(x)
100 loops, best of 3: 16.2 ms per loop

In [59]: %timeit using_digitize(x)
10 loops, best of 3: 27 ms per loop

Для малих масивів using_argsort_twiceможе бути швидше:

In [78]: x = np.random.random(10**2)

In [81]: %timeit using_argsort_twice(x)
100000 loops, best of 3: 3.45 µs per loop

In [79]: %timeit using_indexed_assignment(x)
100000 loops, best of 3: 4.78 µs per loop

In [80]: %timeit using_rankdata(x)
100000 loops, best of 3: 19 µs per loop

In [82]: %timeit using_digitize(x)
10000 loops, best of 3: 26.2 µs per loop

Зауважте також, що stats.rankdataви надаєте більше контролю над тим, як обробляти елементи, що мають однакове значення.


1
Чи можете ви додати трохи пояснень, чому застосування argsort () двічі дає нам ранг?
Фані

1
@Phani: argsortповертає індекси відсортованого масиву. Індекс відсортованих індексів - це ранг. Це те, що argsortповертається другий дзвінок .
unutbu

2
Перший аргумент повертає перестановку (яка, якщо застосовуватись до даних, сортуватиме її). Коли аргумент застосовується до (цієї чи будь-якої) перестановки, він повертає зворотну перестановку (якщо дві перестановки застосовуються один до одного в будь-якому порядку, то результат - Ідентичність). Друга перестановка, якщо застосовувати її до відсортованого масиву даних, створює несортований масив даних, тобто це ранг.
Алекс C

1
Розум подув. Я нарешті зрозумів це! Він повертає масив, вміст якого є індексами вихідного масиву в упорядкованому порядку.
Хосе А

3

У документації йдеться, argsort:

Повертає індекси, які б сортували масив.

Це означає, що перший елемент арґсорту - це індекс елемента, який слід впорядкувати перший, другий - індекс елемента, який повинен бути другим тощо.

Те, що вам здається, хочеться - це порядок ранжування значень, який забезпечується scipy.stats.rankdata. Зауважте, що вам потрібно подумати про те, що має статися, якщо у званнях є зв’язки.


3

numpy.argsort (a, вісь = -1, kind = 'quicksort', order = None)

Повертає індекси, які б сортували масив

Виконайте непряме сортування по заданій осі, використовуючи алгоритм, визначений ключовим словом типу. Він повертає масив індексів тієї ж форми, що і дані індексу вздовж даної осі, у відсортованому порядку.

Розглянемо один приклад в python, що має список значень як

listExample  = [0 , 2, 2456,  2000, 5000, 0, 1]

Тепер ми використовуємо функцію argsort:

import numpy as np
list(np.argsort(listExample))

Вихід буде

[0, 5, 6, 1, 3, 2, 4]

Це перелік індексів значень у listExample, якщо ви порівнюєте ці індекси з відповідними значеннями, то ми отримаємо результат наступним чином:

[0, 0, 1, 2, 2000, 2456, 5000]

(Я вважаю цю функцію дуже корисною у багатьох місцях, наприклад, якщо ви хочете сортувати список / масив, але не хочете використовувати функцію list.sort () (тобто без зміни порядку фактичних значень у списку), ви можете використовувати цю функцію функція.)

Більш детальну інформацію можна знайти за цим посиланням: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html


1

вхід:
імпорт numpy як np
x = np.array ([1.48,1.41,0.0,0.1])
x.argsort (). argsort ()

вихід:
масив ([3, 2, 0, 1])


1
Хоча цей фрагмент коду може бути вирішенням, зокрема пояснення дійсно допомагає покращити якість вашої публікації. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду.
миротип


0

np.argsort повертає індекс відсортованого масиву, заданий 'kind' (який визначає тип алгоритму сортування). Однак, коли список використовується з np.argmax, він повертає індекс найбільшого елемента в списку. Хоча, np.sort, сортує заданий масив, список.


0

Просто хочу прямо протиставити початкове розуміння ОП проти фактичної реалізації з кодом.

numpy.argsort визначається таким чином, що для 1D масивів:

x[x.argsort()] == numpy.sort(x) # this will be an array of True's

OP спочатку вважав, що він визначений таким чином, що для 1D масивів:

x == numpy.sort(x)[x.argsort()] # this will not be True

Примітка: Цей код не працює в загальному випадку (працює лише для 1D), ця відповідь є виключно для ілюстрації.


x[x.argsort()]не обов'язково те саме, що np.sort(x). Насправді це не обов’язково навіть однакової форми. Спробуйте це з 2D-масивом. Це трапляється лише для роботи з 1D-масивами.
Натан

Я відчуваю, що це непотрібно педантично. Питання про 1D масиви. Це призначено як спосіб зрозуміти, в чому різниця, а не буквальний код, який потрібно використовувати. Крім того, якщо у вас є двовимірний масив, навіть не зрозуміло, який сортування ви хочете. Ви хочете глобального сорту? Якщо ні, то яку вісь слід сортувати? Незалежно від цього я додав відмову.
Multihunter

0

Він повертає індекси відповідно до заданих індексів масиву [1.48,1.41,0.0,0.1], це означає: 0.0є першим елементом в індексі [2]. 0.1є другим елементом, в індексі [3]. 1.41є третім елементом в індексі [1]. 1.48є четвертим елементом в індексі [0]. Вихід:

[2,3,1,0]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.