Mam tablicę liczb i chciałbym utworzyć kolejną tablicę, która reprezentuje pozycję każdego elementu w pierwszej tablicy. Używam Pythona i NumPy.
Na przykład:
array = [4,2,7,1]
ranks = [2,1,3,0]
Oto najlepsza metoda, jaką wymyśliłem:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]
Czy istnieją lepsze / szybsze metody, które pozwalają uniknąć dwukrotnego sortowania tablicy?
ranks = temp.argsort()
.Odpowiedzi:
Użyj krojenia po lewej stronie w ostatnim kroku:
Pozwala to uniknąć podwójnego sortowania poprzez odwrócenie permutacji w ostatnim kroku.
źródło
Użyj argsort dwukrotnie, najpierw w celu uzyskania kolejności tablicy, a następnie w celu uzyskania rankingu:
Kiedy mamy do czynienia z tablicami 2D (lub wyższymi wymiarami), należy przekazać argument osi do argsort, aby uporządkować właściwą oś.
źródło
[4,2,7,1,1]
), Dane wyjściowe[3,2,4,0,1]
argsort
.array = np.random.rand(10)
powinna byćarray = np.random.rand(n)
.To pytanie ma już kilka lat, a przyjęta odpowiedź jest świetna, ale myślę, że nadal warto wspomnieć o następujących. Jeśli nie masz nic przeciwko uzależnieniu od
scipy
, możesz użyćscipy.stats.rankdata
:Fajną cechą programu
rankdata
jest to, żemethod
argument zapewnia kilka opcji obsługi powiązań. Na przykład istnieją trzy wystąpienia liczby 20 i dwa wystąpienia liczby 40 wb
:Domyślnie przypisuje średnią rangę do powiązanych wartości:
method='ordinal'
przypisuje kolejne stopnie:method='min'
przypisuje minimalną rangę powiązanych wartości wszystkim powiązanym wartościom:Więcej opcji można znaleźć w dokumentacji.
źródło
rankdata
wydaje się , że wykorzystuje ten sam mechanizm, co przyjęta odpowiedź, do wewnętrznego generowania wstępnego rankingu.Próbowałem rozszerzyć oba rozwiązania dla tablic A o więcej niż jednym wymiarze, zakładając, że przetwarzasz tablicę wiersz po wierszu (oś = 1).
Pierwszy kod rozszerzyłem o pętlę na wierszach; prawdopodobnie można to poprawić
A druga, idąc za sugestią k.rooijers, staje się:
Wygenerowałem losowo 400 tablic z kształtem (1000,100); pierwszy kod zajął około 7,5, drugi 3,8.
źródło
Zobacz wektoryzowaną wersję uśrednionej rangi poniżej. Uwielbiam np. Unikalne, naprawdę poszerza zakres tego, jaki kod można, a czego nie można efektywnie wektoryzować. Oprócz unikania pętli for w Pythonie, to podejście pozwala również uniknąć niejawnej podwójnej pętli nad „a”.
źródło
Oprócz elegancji i krótkości rozwiązań pojawia się również kwestia wykonania. Oto mały punkt odniesienia:
źródło
rankdata(l, method='ordinal') - 1
.Użyj argsort () dwa razy, aby to zrobić:
źródło
Wypróbowałem powyższe metody, ale nie udało mi się, ponieważ miałem wiele zeores. Tak, nawet z pływakami zduplikowane elementy mogą być ważne.
Napisałem więc zmodyfikowane rozwiązanie 1D, dodając krok sprawdzania powiązania:
Uważam, że jest tak skuteczny, jak to tylko możliwe.
źródło
Podobała mi się metoda autorstwa k.rooijers, ale jak napisał rcoup, powtarzające się liczby są uszeregowane według pozycji tablicy. To nie było dla mnie dobre, więc zmodyfikowałem wersję, aby postprocesować rangi i scalić wszystkie powtarzające się liczby w łączną średnią rangę:
Mam nadzieję, że to może pomóc również innym, próbowałem znaleźć inne rozwiązanie tego problemu, ale nie mogłem znaleźć ...
źródło
argsort i slice są operacjami symetrii.
spróbuj dwukrotnie wyciąć zamiast argsort dwa razy. ponieważ slice jest szybszy niż argsort
źródło
Bardziej ogólna wersja jednej z odpowiedzi:
Zobacz Jak używać numpy.argsort () jako indeksów w więcej niż 2 wymiarach? uogólniać na bardziej przyciemnione.
źródło