Eu tenho uma matriz de números e gostaria de criar outra matriz que representa a classificação de cada item na primeira matriz. Estou usando Python e NumPy.
Por exemplo:
array = [4,2,7,1]
ranks = [2,1,3,0]
Este é o melhor método que desenvolvi:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]
Há algum método melhor / mais rápido que evite classificar a matriz duas vezes?
ranks = temp.argsort()
.Respostas:
Use o fatiamento do lado esquerdo na última etapa:
Isso evita a classificação duas vezes, invertendo a permutação na última etapa.
fonte
Use argsort duas vezes, primeiro para obter a ordem da matriz e, em seguida, para obter a classificação:
Ao lidar com matrizes 2D (ou dimensões superiores), certifique-se de passar um argumento de eixo para argsort para ordenar sobre o eixo correto.
fonte
[4,2,7,1,1]
), A saída classificará esses números com base na posição da matriz ([3,2,4,0,1]
)argsort
.array = np.random.rand(10)
deve serarray = np.random.rand(n)
.Essa pergunta tem alguns anos, e a resposta aceita é ótima, mas acho que o seguinte ainda vale a pena mencionar. Se você não se importa com a dependência
scipy
, pode usarscipy.stats.rankdata
:Um bom recurso do
rankdata
é que omethod
argumento fornece várias opções para lidar com empates. Por exemplo, existem três ocorrências de 20 e duas ocorrências de 40 emb
:O padrão atribui a classificação média aos valores empatados:
method='ordinal'
atribui classificações consecutivas:method='min'
atribui a classificação mínima dos valores empatados a todos os valores empatados:Veja a docstring para mais opções.
fonte
rankdata
parece usar o mesmo mecanismo que a resposta aceita para gerar a classificação inicial internamente.Tentei estender ambas as soluções para matrizes A de mais de uma dimensão, supondo que você processe sua matriz linha por linha (eixo = 1).
Estendi o primeiro código com um loop em linhas; provavelmente pode ser melhorado
E o segundo, seguindo a sugestão de k.rooijers, torna-se:
Eu gerei aleatoriamente 400 matrizes com forma (1000,100); o primeiro código demorou cerca de 7,5, o segundo 3,8.
fonte
Para uma versão vetorizada de uma classificação média, veja abaixo. Eu amo o np.unique, ele realmente amplia o escopo do código que pode e não pode ser vetorizado com eficiência. Além de evitar python for-loops, essa abordagem também evita o duplo loop implícito sobre 'a'.
fonte
Além da elegância e da brevidade das soluções, há também a questão do desempenho. Aqui está uma pequena referência:
fonte
rankdata(l, method='ordinal') - 1
.Use argsort () duas vezes:
fonte
Tentei os métodos acima, mas falhei porque tinha muitos zeores. Sim, mesmo com flutuadores, itens duplicados podem ser importantes.
Então, escrevi uma solução 1D modificada adicionando uma etapa de verificação de empate:
Acredito que seja o mais eficiente possível.
fonte
Gostei do método de k.rooijers, mas, como escreveu rcoup, os números repetidos são classificados de acordo com a posição do array. Isso não foi bom para mim, então modifiquei a versão para pós-processar as classificações e mesclar quaisquer números repetidos em uma classificação média combinada:
Espero que ajude outras pessoas também, tentei encontrar outra solução para isso, mas não consegui encontrar ...
fonte
argsort e slice são operações de simetria.
tente slice duas vezes em vez de argsort duas vezes. já que o slice é mais rápido do que argsort
fonte
Versão mais geral de uma das respostas:
Consulte Como usar numpy.argsort () como índices em mais de 2 dimensões? para generalizar para mais escurecimentos.
fonte