Pandas Python: obtém o índice de linhas cuja coluna corresponde a determinado valor

277

Dado um DataFrame com uma coluna "BoolCol", queremos encontrar os índices do DataFrame nos quais os valores para "BoolCol" == True

Atualmente, tenho a maneira iterativa de fazer isso, que funciona perfeitamente:

for i in range(100,3000):
    if df.iloc[i]['BoolCol']== True:
         print i,df.iloc[i]['BoolCol']

Mas essa não é a maneira correta de o panda fazer isso. Após algumas pesquisas, atualmente estou usando este código:

df[df['BoolCol'] == True].index.tolist()

Este me dá uma lista de índices, mas eles não coincidem, quando eu os checo fazendo:

df.iloc[i]['BoolCol']

O resultado é realmente falso !!

Qual seria a maneira correta de os pandas fazerem isso?

Eu quero distintivos
fonte

Respostas:

429

df.iloc[i]retorna a ithlinha de df. inão se refere ao rótulo do índice, ié um índice baseado em 0.

Por outro lado, o atributo indexretorna rótulos de índice reais , não índices de linhas numéricos:

df.index[df['BoolCol'] == True].tolist()

ou equivalente,

df.index[df['BoolCol']].tolist()

Você pode ver a diferença claramente jogando com um DataFrame com um índice não padrão que não é igual à posição numérica da linha:

df = pd.DataFrame({'BoolCol': [True, False, False, True, True]},
       index=[10,20,30,40,50])

In [53]: df
Out[53]: 
   BoolCol
10    True
20   False
30   False
40    True
50    True

[5 rows x 1 columns]

In [54]: df.index[df['BoolCol']].tolist()
Out[54]: [10, 40, 50]

Se você deseja usar o índice ,

In [56]: idx = df.index[df['BoolCol']]

In [57]: idx
Out[57]: Int64Index([10, 40, 50], dtype='int64')

então você pode selecionar as linhas usando em locvez deiloc :

In [58]: df.loc[idx]
Out[58]: 
   BoolCol
10    True
40    True
50    True

[3 rows x 1 columns]

Observe que loctambém pode aceitar matrizes booleanas :

In [55]: df.loc[df['BoolCol']]
Out[55]: 
   BoolCol
10    True
40    True
50    True

[3 rows x 1 columns]

Se você possui uma matriz booleana maske precisa de valores de índice ordinal, pode calculá-los usandonp.flatnonzero :

In [110]: np.flatnonzero(df['BoolCol'])
Out[112]: array([0, 3, 4])

Use df.ilocpara selecionar linhas por índice ordinal:

In [113]: df.iloc[np.flatnonzero(df['BoolCol'])]
Out[113]: 
   BoolCol
10    True
40    True
50    True
unutbu
fonte
9
Ainda outra maneira é fazer df.query('BoolCol').
Phillip Cloud
3
Eu sei que isso é antigo, mas estou me perguntando se existe uma maneira fácil de obter os números de índice baseados em 0 de uma consulta. Preciso dos números iloc porque desejo selecionar algumas linhas antes e depois de uma linha que atenda a uma determinada condição. Portanto, meu plano era obter os índices 0 das linhas que atendessem à condição e criar fatias para uso em iloc (). A única coisa que vejo é get_loc, mas não pode levar uma matriz.
Sheridp
3
@ Sheridp: Se você tiver uma máscara booleana, poderá encontrar os índices ordinais onde maskestá Trueusando np.flatnonzero. Editei a postagem acima para mostrar o que quero dizer.
Unutbu
8
Sua sugestão indices = np.flatnonzero(df[col_name] == category_name)mostra exatamente o que o título da pergunta pede, o que é surpreendentemente difícil de encontrar na Internet.
perfil completo de ClimbsRocks
Se você deseja apenas o índice de volta, qual é a sobrecarga de df [dftest] .index? Isso cria um quadro de dados intermediário (cujos dados podem ser gibabytes). E o dftest? Isso também não aloca um objeto intermediário muito grande, onde o índice retornado pode ser muito pequeno ou mesmo vazio. Estes são magicamente otimizados usando vistas preguiçosas. Se não, então certamente deve haver uma maneira eficiente.
User48956
31

Pode ser feito usando a função numpy where ():

import pandas as pd
import numpy as np

In [716]: df = pd.DataFrame({"gene_name": ['SLC45A1', 'NECAP2', 'CLIC4', 'ADC', 'AGBL4'] , "BoolCol": [False, True, False, True, True] },
       index=list("abcde"))

In [717]: df
Out[717]: 
  BoolCol gene_name
a   False   SLC45A1
b    True    NECAP2
c   False     CLIC4
d    True       ADC
e    True     AGBL4

In [718]: np.where(df["BoolCol"] == True)
Out[718]: (array([1, 3, 4]),)

In [719]: select_indices = list(np.where(df["BoolCol"] == True)[0])

In [720]: df.iloc[select_indices]
Out[720]: 
  BoolCol gene_name
b    True    NECAP2
d    True       ADC
e    True     AGBL4

Embora você nem sempre precise de um índice para uma correspondência, mas caso precise:

In [796]: df.iloc[select_indices].index
Out[796]: Index([u'b', u'd', u'e'], dtype='object')

In [797]: df.iloc[select_indices].index.tolist()
Out[797]: ['b', 'd', 'e']
Surya
fonte
2

A maneira simples é redefinir o índice do DataFrame antes da filtragem:

df_reset = df.reset_index()
df_reset[df_reset['BoolCol']].index.tolist()

Um pouco hacky, mas é rápido!

Ben Druitt
fonte
1

Primeiro você pode verificar queryquando a coluna de destino é do tipo bool (PS: sobre como usá-la, verifique o link )

df.query('BoolCol')
Out[123]: 
    BoolCol
10     True
40     True
50     True

Depois de filtrar o df original pela coluna booleana, podemos escolher o índice.

df=df.query('BoolCol')
df.index
Out[125]: Int64Index([10, 40, 50], dtype='int64')

Também pandas têm nonzero, nós só selecionar a posição de Truelinha e usá-lo cortar o DataFrameouindex

df.index[df.BoolCol.nonzero()[0]]
Out[128]: Int64Index([10, 40, 50], dtype='int64')
YOBEN_S
fonte
1

Se você deseja usar o objeto dataframe apenas uma vez, use:

df['BoolCol'].loc[lambda x: x==True].index
mbh86
fonte
0

Eu estendi esta pergunta que é como obter o row, columnevalue de todo o valor partidas?

aqui está a solução:

import pandas as pd
import numpy as np


def search_coordinate(df_data: pd.DataFrame, search_set: set) -> list:
    nda_values = df_data.values
    tuple_index = np.where(np.isin(nda_values, [e for e in search_set]))
    return [(row, col, nda_values[row][col]) for row, col in zip(tuple_index[0], tuple_index[1])]


if __name__ == '__main__':
    test_datas = [['cat', 'dog', ''],
                  ['goldfish', '', 'kitten'],
                  ['Puppy', 'hamster', 'mouse']
                  ]
    df_data = pd.DataFrame(test_datas)
    print(df_data)
    result_list = search_coordinate(df_data, {'dog', 'Puppy'})
    print(f"\n\n{'row':<4} {'col':<4} {'name':>10}")
    [print(f"{row:<4} {col:<4} {name:>10}") for row, col, name in result_list]

Resultado:

          0        1       2
0       cat      dog        
1  goldfish           kitten
2     Puppy  hamster   mouse


row  col        name
0    1           dog
2    0         Puppy
Carson
fonte