Numpy argsort - o que está fazendo?


123

Por que o numpy está dando esse resultado:

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

>[2 3 1 0]

quando eu esperava fazer isso:

[3 2 0 1]

Claramente, falta minha compreensão da função.


6
Por que você achou [3 2 0 1]que teria sido a resposta correta?
Zwol

9
Eu só tinha uma compreensão invertida da saída. Ou seja, se você pegar o primeiro elemento de x, ele deve estar na posição 3 de uma matriz classificada e assim por diante.
user1276273

26
sua maneira de pensar totalmente faz sentido, eu tinha exatamente a mesma pergunta
adrienlucca.wordpress.com

2
[3 2 0 1] - isto está classificando os valores, você não está obtendo os índices reais.
Lahiru Karunaratne

Apenas para lembrar que a saída indica locais na matriz original enquanto você pensa na matriz classificada. Isso significa que a saída [0] é o índice onde o menor elemento na matriz de entrada original localiza e a saída [-1] para o maior elemento.
lincr

Respostas:


143

De acordo com a documentação

Retorna os índices que ordenariam uma matriz.

  • 2é o índice de 0.0.
  • 3é o índice de 0.1.
  • 1é o índice de 1.41.
  • 0é o índice de 1.48.

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

39

[2, 3, 1, 0] indica que o menor elemento está no índice 2, o menor menor no índice 3, depois no índice 1 e depois no índice 0.

Existem várias maneiras de obter o resultado que você está procurando:

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

Por exemplo,

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

Isso verifica se todos eles produzem o mesmo resultado:

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

Esses %timeitbenchmarks IPython sugerem que para grandes matrizes using_indexed_assignmenté o mais rápido:

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

Para matrizes pequenas, using_argsort_twicepode ser mais rápido:

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

Observe também que stats.rankdatavocê oferece mais controle sobre como lidar com elementos de igual valor.


1
Você pode adicionar alguma explicação sobre por que aplicar argsort () duas vezes nos dá a classificação?
Phani

1
@Phani: argsortretorna os índices da matriz classificada. O índice dos índices classificados é a classificação. É para isso que a segunda chamada argsortretorna.
Unutbu

2
O primeiro argumento retorna uma permutação (que se aplicada aos dados a classificaria). Quando argsort é aplicado a (essa ou qualquer) permutação, ele retorna a permutação inversa (que, se as 2 permutações forem aplicadas uma à outra em qualquer ordem, o resultado será a Identidade). A segunda permutação, se aplicada a uma matriz de dados classificados, produziria a matriz de dados não classificados, ou seja, é a classificação.
Alex C

1
Mente soprada. Eu finalmente entendi! Retorna uma matriz cujo conteúdo são os índices da matriz original em uma ordem classificada.
1813 Jose Jose A

3

Como a documentação diz argsort:

Retorna os índices que ordenariam uma matriz.

Isso significa que o primeiro elemento do argsort é o índice do elemento que deve ser classificado primeiro, o segundo elemento é o índice do elemento que deve ser o segundo, etc.

O que você parece querer é a ordem de classificação dos valores, que é fornecida por scipy.stats.rankdata. Observe que você precisa pensar no que deve acontecer se houver laços nas fileiras.


3

numpy.argsort (a, eixo = -1, tipo = 'classificação rápida', ordem = Nenhuma)

Retorna os índices que ordenariam uma matriz

Execute uma classificação indireta ao longo do eixo especificado, usando o algoritmo especificado pela palavra-chave kind. Ele retorna uma matriz de índices da mesma forma que os dados do índice ao longo do eixo especificado em ordem classificada.

Considere um exemplo em python, com uma lista de valores como

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

Agora usamos a função argsort:

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

A saída será

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

Esta é a lista de índices de valores em listExample, se você mapear esses índices para os respectivos valores, obteremos o resultado da seguinte forma:

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

(Eu acho essa função muito útil em muitos lugares, por exemplo, se você deseja classificar a lista / matriz, mas não deseja usar a função list.sort () (ou seja, sem alterar a ordem dos valores reais na lista), você pode usar isso função.)

Para obter mais detalhes, consulte este link: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html


1

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

saída:
matriz ([3, 2, 0, 1])


1
Embora esse snippet de código possa ser a solução, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
peacetype

0

Primeiro, foi ordenada a matriz. Em seguida, gere uma matriz com o índice inicial da matriz.


0

np.argsort retorna o índice da matriz classificada dada pelo 'kind' (que especifica o tipo de algoritmo de classificação). No entanto, quando uma lista é usada com np.argmax, ele retorna o índice do maior elemento da lista. Enquanto, np.sort, classifica a matriz, lista.


0

Só quero contrastar diretamente o entendimento original do OP em relação à implementação real com o código.

numpy.argsort é definido de modo que, para matrizes 1D:

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

O OP originalmente pensava que estava definido de tal forma que, para as matrizes 1D:

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

Nota: Este código não funciona no caso geral (funciona apenas para 1D), esta resposta é meramente ilustrativa.


x[x.argsort()]não é necessariamente o mesmo que np.sort(x). Na verdade, não é necessariamente nem a mesma forma. Tente isso com uma matriz 2D. Isso acontece apenas com matrizes 1D.
1957 Nathan

Eu sinto que isso é desnecessariamente pedante. A questão é sobre matrizes 1D. Isso pretende ser uma maneira de entender qual era a diferença, em vez de usar um código literal. Além disso, quando você tem uma matriz 2D, nem fica claro que tipo de classificação você deseja. Você quer uma classificação global? Caso contrário, qual eixo deve ser classificado? Independentemente disso, adicionei um aviso.
Multihunter

0

Ele retorna índices de acordo com os índices de matriz fornecidos [1.48,1.41,0.0,0.1], ou seja: 0.0é o primeiro elemento, no índice [2]. 0.1é o segundo elemento, no índice [3]. 1.41é o terceiro elemento, no índice [1]. 1.48é o quarto elemento, no índice [0]. Resultado:

[2,3,1,0]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.