Encontre a linha onde os valores da coluna são máximos em um DataFrame do pandas

209

Como posso encontrar a linha para a qual o valor de uma coluna específica é máximo ?

df.max() vai me dar o valor máximo para cada coluna, não sei como obter a linha correspondente.

lazy1
fonte
É possível obter os 2 principais valores? em vez de apenas o máximo?
AsheKetchum
5
Você pode usar sort_valuese obter o índice:df.sort_values('col', ascending=False)[:2].index
lazy1 17/17
2
lazy1: evite classificar desnecessariamente uma série inteira porque é O (N logN) em média, enquanto encontrar max / idxmax é apenas O (N).
smci 16/07/19

Respostas:

240

Use a idxmaxfunção pandas . É simples:

>>> import pandas
>>> import numpy as np
>>> df = pandas.DataFrame(np.random.randn(5,3),columns=['A','B','C'])
>>> df
          A         B         C
0  1.232853 -1.979459 -0.573626
1  0.140767  0.394940  1.068890
2  0.742023  1.343977 -0.579745
3  2.125299 -0.649328 -0.211692
4 -0.187253  1.908618 -1.862934
>>> df['A'].argmax()
3
>>> df['B'].argmax()
4
>>> df['C'].argmax()
1
  • Como alternativa, você também pode usar numpy.argmax, como numpy.argmax(df['A'])- ele fornece a mesma coisa e aparece pelo menos tão rápido quanto idxmaxem observações superficiais.

  • idxmax() retorna rótulos de índices, não números inteiros.

    • Exemplo ': se você tiver valores de sequência como seus rótulos de índice, como as linhas' a 'a' e ', convém saber que o máximo ocorre na linha 4 (não na linha' d ').
    • se você quiser a posição inteira desse rótulo dentro da etiqueta, Indexprecisará obtê-lo manualmente (o que pode ser complicado agora que rótulos de linha duplicados são permitidos).

NOTAS HISTÓRICAS:

  • idxmax()costumava ser chamado argmax()antes de 0.11
  • argmax foi preterido antes da 1.0.0 e removido inteiramente na 1.0.0
  • de volta ao Pandas 0.16, argmaxexistia e desempenhava a mesma função (embora parecesse rodar mais lentamente que idxmax).
    • argmaxA função retornou a posição inteira no índice do local da linha do elemento máximo.
    • os pandas passaram a usar rótulos de linha em vez de índices inteiros. Os índices inteiros posicionais costumavam ser muito comuns, mais comuns que os rótulos, especialmente em aplicativos onde rótulos de linha duplicados são comuns.

Por exemplo, considere este brinquedo DataFramecom um rótulo de linha duplicado:

In [19]: dfrm
Out[19]: 
          A         B         C
a  0.143693  0.653810  0.586007
b  0.623582  0.312903  0.919076
c  0.165438  0.889809  0.000967
d  0.308245  0.787776  0.571195
e  0.870068  0.935626  0.606911
f  0.037602  0.855193  0.728495
g  0.605366  0.338105  0.696460
h  0.000000  0.090814  0.963927
i  0.688343  0.188468  0.352213
i  0.879000  0.105039  0.900260

In [20]: dfrm['A'].idxmax()
Out[20]: 'i'

In [21]: dfrm.iloc[dfrm['A'].idxmax()]  # .ix instead of .iloc in older versions of pandas
Out[21]: 
          A         B         C
i  0.688343  0.188468  0.352213
i  0.879000  0.105039  0.900260

Portanto, aqui um uso ingênuo de idxmaxnão é suficiente, enquanto a forma antiga de argmaxforneceria corretamente a localização posicional da linha máxima (neste caso, posição 9).

Esse é exatamente um daqueles tipos desagradáveis ​​de comportamentos propensos a erros em linguagens dinamicamente tipadas que tornam esse tipo de coisa tão infeliz e que vale a pena bater em um cavalo morto. Se você estiver gravando código do sistema e seu sistema for subitamente usado em alguns conjuntos de dados que não são limpos corretamente antes de ingressar, é muito fácil acabar com rótulos de linha duplicados, especialmente rótulos de string, como um identificador CUSIP ou SEDOL para ativos financeiros. Você não pode usar facilmente o sistema de tipos para ajudá-lo e talvez não consiga impor exclusividade no índice sem encontrar dados inesperadamente ausentes.

Portanto, você tem a esperança de que seus testes de unidade abranjam tudo (eles não o fizeram, ou mais provavelmente ninguém escreveu nenhum teste) - caso contrário (provavelmente), você ficará esperando para ver se está de acordo com isso. erro em tempo de execução; nesse caso, você provavelmente precisará gastar muitas horas de trabalho no banco de dados para o qual estava produzindo resultados, bater a cabeça contra a parede no IPython, tentando reproduzir manualmente o problema, finalmente descobrindo que é porque idxmax pode reporte o rótulo da linha máxima e, em seguida, desapontado por nenhuma função padrão obter automaticamente as posições da linha máxima para você, escrevendo você mesmo uma implementação de buggy, editando o código e rezando para que você não tenha problemas novamente.

ely
fonte
13
Com base no penúltimo comentário, parece argmine argmaxcontinuará fazendo parte, DataFramee a diferença é apenas se você deseja o índice ou o rótulo. idxmaxfornecerá o rótulo do local em que ocorre um máximo. argmaxlhe dará o inteiro inteiro do índice.
ely
4
As informações fornecidas para explicar a diferença entre argmaxe idxmaxe como evitar bugs com índice duplicado foram ótimas! Não notei isso até ler seu comentário na outra resposta. Obrigado!
tupan
Com relação ao uso que você gostaria de implementar, o Pandas 0.24.1 aponta para o seguinte: 'o comportamento de argmaxserá corrigido para retornar o máximo posicional no futuro. Por enquanto, use series.values.argmaxou np.argmax(np.array(values))para obter a posição da linha máxima.
Sam
1
da mesma forma, o .ixmétodo do segundo exemplo foi renomeado para.iloc
Ma0 30/10/19
se sua coluna contiver apenas valores nan, isso resultará em TypeError
Max Segal
77

Você também pode tentar idxmax:

In [5]: df = pandas.DataFrame(np.random.randn(10,3),columns=['A','B','C'])

In [6]: df
Out[6]: 
          A         B         C
0  2.001289  0.482561  1.579985
1 -0.991646 -0.387835  1.320236
2  0.143826 -1.096889  1.486508
3 -0.193056 -0.499020  1.536540
4 -2.083647 -3.074591  0.175772
5 -0.186138 -1.949731  0.287432
6 -0.480790 -1.771560 -0.930234
7  0.227383 -0.278253  2.102004
8 -0.002592  1.434192 -1.624915
9  0.404911 -2.167599 -0.452900

In [7]: df.idxmax()
Out[7]: 
A    0
B    8
C    7

por exemplo

In [8]: df.loc[df['A'].idxmax()]
Out[8]: 
A    2.001289
B    0.482561
C    1.579985
Wes McKinney
fonte
Obrigado Wes. Documentação para idxmax () aqui: pandas.pydata.org/pandas-docs/dev/generated/…
será
df.ix[df['A'].idxmax()].valuespara pegar o array que eu queria. ainda funciona.
Yojimbo 19/02
2
Observe que você precisa ter cuidado ao tentar usar a saída idxmaxcomo um alimentador ixou loccomo um meio para subdividir os dados e / ou obter a localização posicional da linha máxima. Porque você pode ter duplicados no Index- veja a atualização da minha resposta para um exemplo.
Ely
25

As duas respostas acima retornariam apenas um índice se houver várias linhas que levam o valor máximo. Se você deseja todas as linhas, parece não ter uma função. Mas não é difícil de fazer. Abaixo está um exemplo para a série; o mesmo pode ser feito para o DataFrame:

In [1]: from pandas import Series, DataFrame

In [2]: s=Series([2,4,4,3],index=['a','b','c','d'])

In [3]: s.idxmax()
Out[3]: 'b'

In [4]: s[s==s.max()]
Out[4]: 
b    4
c    4
dtype: int64
mxia
fonte
10
Obrigado! versão para DataFrame:df[df['A'] == df['A'].max()]
Dennis Golomazov 12/10
Esta é a resposta realmente correta (a versão do DataFrame).
gented
12
df.iloc[df['columnX'].argmax()]

argmax()forneceria o índice correspondente ao valor máximo da colunaX. ilocpode ser usado para obter a linha do DataFrame df para este índice.

Nafeez Quraishi
fonte
4

A solução direta ".argmax ()" não funciona para mim.

O exemplo anterior fornecido por @ely

>>> import pandas
>>> import numpy as np
>>> df = pandas.DataFrame(np.random.randn(5,3),columns=['A','B','C'])
>>> df
      A         B         C
0  1.232853 -1.979459 -0.573626
1  0.140767  0.394940  1.068890
2  0.742023  1.343977 -0.579745
3  2.125299 -0.649328 -0.211692
4 -0.187253  1.908618 -1.862934
>>> df['A'].argmax()
3
>>> df['B'].argmax()
4
>>> df['C'].argmax()
1

retorna a seguinte mensagem:

FutureWarning: 'argmax' is deprecated, use 'idxmax' instead. The behavior of 'argmax' 
will be corrected to return the positional maximum in the future.
Use 'series.values.argmax' to get the position of the maximum now.

Para que minha solução seja:

df['A'].values.argmax()
AntoineP
fonte
2
mx.iloc[0].idxmax()

Essa linha de código fornecerá como encontrar o valor máximo de uma linha no dataframe, aqui mxestá o dataframe e iloc[0]indica o 0º índice.

Manjula Devi
fonte
1

O idmaxDataFrame retorna o índice de rótulo da linha com o valor máximo e o comportamento de argmaxdepende da versão de pandas(no momento, ele retorna um aviso). Se você deseja usar o índice posicional , pode fazer o seguinte:

max_row = df['A'].values.argmax()

ou

import numpy as np
max_row = np.argmax(df['A'].values)

Observe que se você usar np.argmax(df['A'])se comporta da mesma forma que df['A'].argmax().

Jonathan
fonte