Python Pandas: obtiene el índice de filas donde la columna coincide con cierto valor
Dado un DataFrame con una columna "BoolCol", queremos encontrar los índices del DataFrame en los que los valores de "BoolCol" == True
Actualmente tengo la forma iterativa de hacerlo, que funciona perfectamente:
for i in range(100,3000):
if df.iloc[i]['BoolCol']== True:
print i,df.iloc[i]['BoolCol']
Pero esta no es la forma correcta de hacerlo para los pandas. Después de investigar un poco, actualmente estoy usando este código:
df[df['BoolCol'] == True].index.tolist()
Éste me da una lista de índices, pero no coinciden cuando los reviso haciendo:
df.iloc[i]['BoolCol']
¡¡El resultado es realmente Falso!!
¿Cuál sería la forma correcta de hacer esto para los pandas?
df.iloc[i]
devuelve la ith
fila de df
. i
no hace referencia a la etiqueta del índice, i
es un índice basado en 0.
Por el contrario, el atributo index
devuelve etiquetas de índice reales , no índices de filas numéricos:
df.index[df['BoolCol'] == True].tolist()
o equivalente,
df.index[df['BoolCol']].tolist()
Puedes ver la diferencia con bastante claridad jugando con un DataFrame con un índice no predeterminado que no es igual a la posición numérica de la fila:
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]
Si desea utilizar el índice ,
In [56]: idx = df.index[df['BoolCol']]
In [57]: idx
Out[57]: Int64Index([10, 40, 50], dtype='int64')
luego puedes seleccionar las filas usando loc
en lugar deiloc
:
In [58]: df.loc[idx]
Out[58]:
BoolCol
10 True
40 True
50 True
[3 rows x 1 columns]
Tenga en cuenta que loc
también puede aceptar matrices booleanas :
In [55]: df.loc[df['BoolCol']]
Out[55]:
BoolCol
10 True
40 True
50 True
[3 rows x 1 columns]
Si tiene una matriz booleana mask
y necesita valores de índice ordinales, puede calcularlos usandonp.flatnonzero
:
In [110]: np.flatnonzero(df['BoolCol'])
Out[112]: array([0, 3, 4])
Úselo df.iloc
para seleccionar filas por índice ordinal:
In [113]: df.iloc[np.flatnonzero(df['BoolCol'])]
Out[113]:
BoolCol
10 True
40 True
50 True
Se puede hacer usando la función 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
Aunque no siempre necesitas un índice para una coincidencia, en caso de que necesites:
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']
Si desea utilizar su objeto de marco de datos solo una vez, utilice:
df['BoolCol'].loc[lambda x: x==True].index
Una forma sencilla es restablecer el índice del DataFrame antes del filtrado:
df_reset = df.reset_index()
df_reset[df_reset['BoolCol']].index.tolist()
¡Un poco complicado, pero es rápido!