Numpy argsort - что он делает?


123

Почему numpy дает такой результат:

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 отсортированного массива и так далее.
user1276273

26
ваш образ мышления имеет смысл, у меня был точно такой же вопрос
adrienlucca.wordpress.com

2
[3 2 0 1] - это ранжирование значений, вы не получаете фактических индексов.
Лахиру Карунаратне

Просто помните, что выходные данные указывают местоположения в исходном массиве, в то время как вы думаете, что это в отсортированном массиве. Это означает, что output [0] - это индекс, по которому находится наименьший элемент исходного входного массива, а output [-1] - самый большой элемент.
lincr

Ответы:


145

Согласно документации

Возвращает индексы для сортировки массива.

  • 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])
Belter

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 () дает нам рейтинг?
Phani

1
@Phani: argsortвозвращает индексы отсортированного массива. Индекс отсортированных индексов - это ранг. Это то, что argsortвозвращает второй вызов .
unutbu

2
Первый argsort возвращает перестановку (которая, если применить ее к данным, сортирует ее). Когда argsort применяется к (этой или любой) перестановке, он возвращает обратную перестановку (то есть, если 2 перестановки применяются друг к другу в любом порядке, результатом будет Identity). Вторая перестановка, если она применяется к отсортированному массиву данных, приведет к созданию несортированного массива данных, то есть это ранг.
Alex C

1
Разум взорван. Я наконец понял это! Он возвращает массив, содержимое которого является индексами исходного массива в отсортированном порядке.
Jose A

3

Как говорится в документацииargsort :

Возвращает индексы для сортировки массива.

Это означает, что первый элемент argsort - это индекс элемента, который должен быть отсортирован первым, второй элемент - это индекс элемента, который должен быть вторым и т. Д.

Кажется, вам нужен порядок ранжирования значений, который предоставляется scipy.stats.rankdata. Учтите, что нужно подумать о том, что должно произойти, если в строю будет ничья.


3

numpy.argsort (a, axis = -1, kind = 'quicksort', order = None)

Возвращает индексы для сортировки массива

Выполните косвенную сортировку по заданной оси, используя алгоритм, заданный ключевым словом kind. Он возвращает массив индексов той же формы, что и данные индекса по заданной оси в отсортированном порядке.

Рассмотрим один пример на 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
Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причины вашего предложения кода.
peacetype


0

np.argsort возвращает индекс отсортированного массива, заданный параметром "kind" (который указывает тип алгоритма сортировки). Однако, когда список используется с np.argmax, он возвращает индекс самого большого элемента в списке. В то время как np.sort сортирует данный массив list.


0

Просто хочу прямо противопоставить исходное понимание OP и фактическую реализацию с кодом.

numpy.argsort определяется так, что для одномерных массивов:

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

OP изначально думал, что он был определен таким образом, что для одномерных массивов:

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

Примечание: этот код не работает в общем случае (работает только для 1D), этот ответ предназначен исключительно для целей иллюстрации.


x[x.argsort()]не обязательно то же самое, что np.sort(x). На самом деле, это даже не обязательно одна и та же форма. Попробуйте это с 2D-массивом. Это происходит только при работе с одномерными массивами.
Натан

Я чувствую, что это излишне педантично. Речь идет об одномерных массивах. Это сделано для того, чтобы понять, в чем разница, а не для использования буквального кода. Кроме того, когда у вас есть 2D-массив, даже неясно, какую сортировку вы хотите. Хотите глобальную сортировку? Если нет, то по какой оси нужно сортировать? Тем не менее, я добавил отказ от ответственности.
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.