Numpy argsort - co to robi?

123

Dlaczego numpy podaje ten wynik:

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

>[2 3 1 0]

kiedy spodziewałbym się, że to zrobi:

[3 2 0 1]

Najwyraźniej brakuje mi zrozumienia tej funkcji.

user1276273
źródło
6
Dlaczego pomyślałeś, że [3 2 0 1]byłaby to poprawna odpowiedź?
zwol
9
Po prostu miałem odwrotne rozumienie wyniku. To znaczy, jeśli weźmiesz pierwszy element x, powinien on znajdować się na pozycji 3 posortowanej tablicy i tak dalej.
user1276273
26
Twój sposób myślenia ma sens, miałem dokładnie to samo pytanie
adrienlucca.wordpress.com
2
[3 2 0 1] - to ranking wartości, nie otrzymujesz rzeczywistych wskaźników.
Lahiru Karunaratne
Wystarczy pamiętać, że dane wyjściowe wskazują lokalizacje w oryginalnej tablicy, podczas gdy myślisz, że w posortowanej tablicy. Oznacza to, że dane wyjściowe [0] to indeks, w którym najmniejszy element oryginalnej tablicy wejściowej lokalizuje i wyprowadza [-1] dla największego elementu.
lincr

Odpowiedzi:

145

Zgodnie z dokumentacją

Zwraca indeksy, które posortowałyby tablicę.

  • 2jest indeksem 0.0.
  • 3jest indeksem 0.1.
  • 1jest indeksem 1.41.
  • 0jest indeksem 1.48.
falsetru
źródło
12
a = x.argsort(), drukuj x[a], dostaniemyarray([ 0. , 0.1 , 1.41, 1.48])
Belter
39

[2, 3, 1, 0] wskazuje, że najmniejszy element znajduje się pod indeksem 2, następny najmniejszy element pod indeksem 3, następnie indeks 1, a następnie indeks 0.

Istnieje kilka sposobów uzyskania wyniku, którego szukasz:

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

Na przykład,

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

To sprawdza, czy wszystkie dają ten sam wynik:

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))

Te %timeittesty porównawcze IPythona sugerują, że dla dużych tablic using_indexed_assignmentsą najszybsze:

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

W przypadku małych tablic using_argsort_twicemoże być szybsze:

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

Zauważ również, że stats.rankdatadaje ci to większą kontrolę nad tym, jak obsługiwać elementy o równej wartości.

unutbu
źródło
1
Czy możesz dodać wyjaśnienie, dlaczego dwukrotne zastosowanie argsort () daje nam rangę?
Phani,
1
@Phani: argsortzwraca indeksy posortowanej tablicy. Indeks posortowanych indeksów to ranga. Oto co argsortpowraca drugie wezwanie .
unutbu
2
Pierwszy argument argsort zwraca permutację (która po zastosowaniu do danych posortowałaby ją). Kiedy argument argsort jest stosowany do (tej lub dowolnej) permutacji, zwraca permutację odwrotną (jeśli te dwie permutacje zostaną zastosowane względem siebie w dowolnej kolejności, wynikiem jest Identity). Druga permutacja zastosowana do posortowanej tablicy danych dałaby nieposortowaną tablicę danych, tj. Jest to ranga.
Alex C
1
Rozumiem. W końcu to zrozumiałem! Zwraca tablicę, której zawartość jest indeksami oryginalnej tablicy w posortowanej kolejności.
Jose A,
3

Jak mówi dokumentacjaargsort :

Zwraca indeksy, które posortowałyby tablicę.

Oznacza to, że pierwszym elementem argsort jest indeks elementu, który powinien być sortowany jako pierwszy, drugi element to indeks elementu, który powinien być drugi itd.

Wydaje się, że chcesz, aby porządek rangi wartości był zapewniony przez scipy.stats.rankdata. Pamiętaj, że musisz pomyśleć o tym, co się stanie, jeśli w szeregach są remisy.

BrenBarn
źródło
3

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

Zwraca indeksy, które posortowałyby tablicę

Wykonaj pośrednie sortowanie wzdłuż danej osi, używając algorytmu określonego przez słowo kluczowe kind. Zwraca tablicę indeksów o tym samym kształcie, co dane indeksu wzdłuż danej osi w posortowanej kolejności.

Rozważ jeden przykład w Pythonie, mając listę wartości jako

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

Teraz używamy funkcji argsort:

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

Wynik będzie

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

To jest lista indeksów wartości na liście Przykład, jeśli odwzorujesz te indeksy na odpowiednie wartości, otrzymamy następujący wynik:

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

(Uważam, że ta funkcja jest bardzo przydatna w wielu miejscach, np. Jeśli chcesz posortować listę / tablicę, ale nie chcesz używać funkcji list.sort () (tj. Bez zmiany kolejności rzeczywistych wartości na liście), możesz użyć tego funkcjonować.)

Więcej informacji można znaleźć pod tym linkiem: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html

Yogesh
źródło
1

wejście:
import numpy as np
x = np.array ([1.48,1.41,0.0,0.1])
x.argsort (). argsort ()

wyjście:
tablica ([3, 2, 0, 1])

JMpony
źródło
1
Chociaż ten fragment kodu może być rozwiązaniem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
Peacetype
0

Najpierw zamówiono tablicę. Następnie wygeneruj tablicę z początkowym indeksem tablicy.

Rodrigo Saraguro
źródło
0

np.argsort zwraca indeks posortowanej tablicy podany przez 'rodzaj' (który określa typ algorytmu sortowania). Jednak gdy lista jest używana z np.argmax, zwraca indeks największego elementu na liście. Natomiast np.sort sortuje podaną tablicę list.

vivek
źródło
0

Po prostu chcę bezpośrednio porównać oryginalne rozumienie OP z rzeczywistą implementacją za pomocą kodu.

numpy.argsort jest zdefiniowany w taki sposób, że dla tablic 1D:

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

OP początkowo uważał, że został zdefiniowany w taki sposób, że dla tablic 1D:

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

Uwaga: ten kod nie działa w ogólnym przypadku (działa tylko dla 1D), ta odpowiedź ma charakter wyłącznie ilustracyjny.

Multihunter
źródło
x[x.argsort()]niekoniecznie jest tym samym, co np.sort(x). W rzeczywistości niekoniecznie ma nawet ten sam kształt. Spróbuj tego z tablicą 2D. Dzieje się tak tylko z tablicami 1D.
Nathan
Wydaje mi się, że to niepotrzebnie pedantyczne. Pytanie dotyczy tablic 1D. Ma to na celu raczej zrozumienie, na czym polegała różnica, niż użycie dosłownego kodu. Ponadto, gdy masz tablicę 2D, nie jest nawet jasne, jakiego rodzaju sortowania chcesz. Chcesz globalnego sortowania? Jeśli nie, którą oś należy sortować? Niezależnie od tego, dodałem zastrzeżenie.
Multihunter
0

Zwraca indeksy zgodnie z podanymi indeksami tablicy, [1.48,1.41,0.0,0.1]czyli: 0.0jest pierwszym elementem w indeksie [2]. 0.1jest drugim elementem w indeksie [3]. 1.41to trzeci element w indeksie [1]. 1.48to czwarty element w indeksie [0]. Wynik:

[2,3,1,0]
nucsit026
źródło