Numpy argsort - cosa sta facendo?


123

Perché numpy dà questo risultato:

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

>[2 3 1 0]

quando mi aspetto che lo faccia:

[3 2 0 1]

Chiaramente la mia comprensione della funzione è carente.


6
Perché pensavi che [3 2 0 1]sarebbe stata la risposta corretta?
zwol

9
Ho appena avuto una comprensione invertita dell'output. Cioè, se prendi il primo elemento di x, dovrebbe essere nella posizione 3 di un array ordinato e così via.
user1276273

26
il tuo modo di pensare ha perfettamente senso, avevo esattamente la stessa domanda
adrienlucca.wordpress.com

2
[3 2 0 1] - questa è la classifica dei valori, non ottieni gli indici effettivi.
Lahiru Karunaratne

Solo per ricordare che l'output indica le posizioni nell'array originale mentre lo pensi nell'array ordinato. Ciò significa che l'output [0] è l'indice in cui si trova l'elemento più piccolo nell'array di input originale e l'output [-1] per l'elemento più grande.
Lincr

Risposte:


144

Secondo la documentazione

Restituisce gli indici che ordinerebbero un array.

  • 2è l'indice di 0.0.
  • 3è l'indice di 0.1.
  • 1è l'indice di 1.41.
  • 0è l'indice di 1.48.

12
a = x.argsort(), stampa x[a], avremoarray([ 0. , 0.1 , 1.41, 1.48])
Belter

39

[2, 3, 1, 0] indica che l'elemento più piccolo è all'indice 2, il successivo più piccolo all'indice 3, quindi all'indice 1, quindi all'indice 0.

Esistono diversi modi per ottenere il risultato che stai cercando:

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

Per esempio,

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

Questo controlla che producano tutti lo stesso risultato:

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

Questi %timeitbenchmark IPython suggeriscono per array di grandi dimensioni using_indexed_assignmentè il più veloce:

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

Per piccoli array, using_argsort_twicepotrebbe essere più veloce:

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

Nota anche che stats.rankdatati dà più controllo su come gestire elementi di uguale valore.


1
Puoi aggiungere qualche spiegazione sul perché l'applicazione di argsort () due volte ci dà il rango?
Phani

1
@Phani: argsortrestituisce gli indici dell'array ordinato. L'indice degli indici ordinati è il rango. Questo è ciò che argsortrestituisce la seconda chiamata a .
unutbu

2
Il primo argsort restituisce una permutazione (che se applicata ai dati lo ordinerebbe). Quando argsort viene applicato a (questa o qualsiasi altra) permutazione, restituisce la permutazione inversa (che se le 2 permutazioni vengono applicate l'una all'altra in qualsiasi ordine il risultato è l'identità). La seconda permutazione se applicata a un array di dati ordinato produrrebbe l'array di dati non ordinato, cioè è il rango.
Alex C

1
Sbalordire. Finalmente l'ho capito! Restituisce un array il cui contenuto è gli indici dell'array originale in un ordine ordinato.
Jose A

3

Come dice la documentazioneargsort :

Restituisce gli indici che ordinerebbero un array.

Ciò significa che il primo elemento dell'argsort è l'indice dell'elemento che dovrebbe essere ordinato per primo, il secondo elemento è l'indice dell'elemento che dovrebbe essere il secondo, ecc.

Quello che sembri desiderare è l'ordine di classificazione dei valori, che è ciò che viene fornito da scipy.stats.rankdata. Nota che devi pensare a cosa dovrebbe accadere se ci sono legami nei ranghi.


3

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

Restituisce gli indici che ordinerebbero un array

Eseguire un ordinamento indiretto lungo l'asse specificato utilizzando l'algoritmo specificato dalla parola chiave kind. Restituisce una matrice di indici della stessa forma dei dati dell'indice lungo l'asse specificato in ordine ordinato.

Considera un esempio in Python, con un elenco di valori come

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

Ora usiamo la funzione argsort:

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

L'output sarà

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

Questo è l'elenco degli indici dei valori in listExample se si mappano questi indici ai rispettivi valori, otterremo il risultato come segue:

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

(Trovo questa funzione molto utile in molti posti, ad esempio se vuoi ordinare l'elenco / array ma non vuoi usare la funzione list.sort () (cioè senza cambiare l'ordine dei valori effettivi nell'elenco) puoi usarlo funzione.)

Per maggiori dettagli fare riferimento a questo link: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html


1

input:
importa numpy come np
x = np.array ([1.48,1.41,0.0,0.1])
x.argsort (). argsort ()

output:
array ([3, 2, 0, 1])


1
Sebbene questo frammento di codice possa essere la soluzione, includere una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
peacetype

0

In primo luogo, è stato ordinato l'array. Quindi genera un array con l'indice iniziale dell'array.


0

np.argsort restituisce l'indice dell'array ordinato fornito da "kind" (che specifica il tipo di algoritmo di ordinamento). Tuttavia, quando un elenco viene utilizzato con np.argmax, restituisce l'indice dell'elemento più grande nell'elenco. Mentre, np.sort, ordina l'array dato, list.


0

Voglio solo confrontare direttamente la comprensione originale dell'OP con l'effettiva implementazione con il codice.

numpy.argsort è definito in modo tale che per gli array 1D:

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

L'OP inizialmente pensava che fosse definito in modo tale che per gli array 1D:

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

Nota: questo codice non funziona nel caso generale (funziona solo per 1D), questa risposta è puramente a scopo illustrativo.


x[x.argsort()]non è necessariamente lo stesso di np.sort(x). In effetti, non è necessariamente nemmeno la stessa forma. Prova questo con un array 2D. Questo accade solo per funzionare con array 1D.
Nathan

Mi sento come se fosse inutilmente pedante. La domanda riguarda gli array 1D. Questo è inteso come un modo per capire quale fosse la differenza, piuttosto che un codice letterale da usare. Inoltre, quando hai un array 2D non è nemmeno chiaro quale tipo di ordinamento desideri. Vuoi un ordinamento globale? In caso negativo, quale asse deve essere ordinato? Indipendentemente da ciò, ho aggiunto un disclaimer.
Multihunter

0

Restituisce gli indici in base agli indici della matrice data,, [1.48,1.41,0.0,0.1]ciò significa: 0.0è il primo elemento, in index [2]. 0.1è il secondo elemento, nell'indice [3]. 1.41è il terzo elemento, nell'indice [1]. 1.48è il quarto elemento, nell'indice [0]. Produzione:

[2,3,1,0]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.