Cómo soltar filas de Pandas DataFrame cuyo valor en una columna determinada es NaN

754

Tengo esto DataFramey solo quiero los registros cuya EPScolumna no es NaN:

>>> df
                 STK_ID  EPS  cash
STK_ID RPT_Date                   
601166 20111231  601166  NaN   NaN
600036 20111231  600036  NaN    12
600016 20111231  600016  4.3   NaN
601009 20111231  601009  NaN   NaN
601939 20111231  601939  2.5   NaN
000001 20111231  000001  NaN   NaN

... es decir, algo así como df.drop(....)obtener este marco de datos resultante:

                  STK_ID  EPS  cash
STK_ID RPT_Date                   
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN

¿Cómo puedo hacer eso?

bicho grande
fuente
177
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
osa

Respuestas:

655

No deje caer, solo tome las filas donde EPS no es NA:

df = df[df['EPS'].notna()]
eumiro
fuente
470
Recomiendo usar en pandas.notnulllugar denp.isfinite
Wes McKinney
11
¿Hay alguna ventaja en indexar y copiar en lugar de soltar?
Robert Muil
99
Crea un error: TypeError: ufunc 'isfinite' no es compatible con los tipos de entrada, y las entradas no se pueden coaccionar de forma segura a ningún tipo compatible de acuerdo con la regla de conversión '' seguro ''
Philipp Schwarz
44
@ wes-mckinney podría hacerme saber si dropna () es una mejor opción sobre pandas.notnull en este caso? Si es así, ¿por qué?
stormfield
44
@PhilippSchwarz Este error ocurre si la columna ( EPSen el ejemplo) contiene cadenas u otros tipos que no pueden ser digeridos np.isfinite(). Recomiendo usar pandas.notnull()que manejará esto más generosamente.
normanius 05 de
902

Esta pregunta ya está resuelta, pero ...

... también considere la solución sugerida por Wouter en su comentario original . La capacidad de manejar datos faltantes, incluidos dropna(), está integrada explícitamente en pandas. Además de un rendimiento potencialmente mejorado sobre hacerlo manualmente, estas funciones también vienen con una variedad de opciones que pueden ser útiles.

In [24]: df = pd.DataFrame(np.random.randn(10,3))

In [25]: df.iloc[::2,0] = np.nan; df.iloc[::4,1] = np.nan; df.iloc[::3,2] = np.nan;

In [26]: df
Out[26]:
          0         1         2
0       NaN       NaN       NaN
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [27]: df.dropna()     #drop all rows that have any NaN values
Out[27]:
          0         1         2
1  2.677677 -1.466923 -0.750366
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295

In [28]: df.dropna(how='all')     #drop only if ALL columns are NaN
Out[28]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [29]: df.dropna(thresh=2)   #Drop row if it does not have at least two values that are **not** NaN
Out[29]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

In [30]: df.dropna(subset=[1])   #Drop only if NaN in specific column (as asked in the question)
Out[30]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

También hay otras opciones (consulte los documentos en http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html ), incluida la colocación de columnas en lugar de filas.

Bastante útil!

Un hombre
fuente
282
También puedes usar df.dropna(subset = ['column_name']). Espero que ahorre al menos a una persona los 5 segundos adicionales de "¿qué estoy haciendo mal?". Gran respuesta, +1
James Tobin
10
@JamesTobin, ¡acabo de pasar 20 minutos para escribir una función para eso! La documentación oficial era muy críptica: "Etiquetas a lo largo de otros ejes a tener en cuenta, por ejemplo, si está soltando filas, estas serían una lista de columnas para incluir". No he podido entender, lo que significaba ...
osa
df.dropna(subset = ['column_name'])es exactamente lo que estaba buscando! ¡Gracias!
amalik2205
123

Sé que esto ya ha sido respondido, pero solo por el bien de una solución puramente panda a esta pregunta específica en oposición a la descripción general de Aman (que fue maravilloso) y en caso de que alguien más se dé cuenta de esto:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Kirk Hadley
fuente
10
En realidad, la respuesta específica sería: df.dropna(subset=['EPS'])(basado en la descripción general de Aman, por supuesto, esto también funciona)
joris
2
notnulles también lo que Wes (autor de Pandas) sugirió en su comentario sobre otra respuesta.
fantabolous
Esta es quizás una pregunta novata. Pero cuando hago un df [pd.notnull (...) o df.dropna, el índice se cae. Entonces, si hubo un valor nulo en el índice de fila 10 en un df de longitud 200. El marco de datos después de ejecutar la función de caída tiene valores de índice de 1 a 9 y luego de 11 a 200. De todos modos para "volver a indexarlo"
Aakash Gupta
también podría hacer df[pd.notnull(df[df.columns[INDEX]])]dónde INDEXestaría la columna numerada si no sabe el nombre
ocean800
60

Puedes usar esto:

df.dropna(subset=['EPS'], how='all', inplace=True)
Joe
fuente
18
how='all'es redundante en este caso, ya que en subconjuntos de trama de datos sólo con un campo para tanto 'all'y 'any'tendrá el mismo efecto.
Anton Protopopov
35

La más simple de todas las soluciones:

filtered_df = df[df['EPS'].notnull()]

La solución anterior es mucho mejor que usar np.isfinite ()

Gil Baggio
fuente
22

Puede usar el método de marco de datos notnull o inverso de isnull o numpy.isnan :

In [332]: df[df.EPS.notnull()]
Out[332]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [334]: df[~df.EPS.isnull()]
Out[334]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [347]: df[~np.isnan(df.EPS)]
Out[347]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN
Anton Protopopov
fuente
10

otra solución que utiliza el hecho de que np.nan != np.nan:

In [149]: df.query("EPS == EPS")
Out[149]:
                 STK_ID  EPS  cash
STK_ID RPT_Date
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN
MaxU
fuente
2

Otra version:

df[~df['EPS'].isna()]
keramat
fuente
¿Por qué usar esto Series.notna()?
AMC
2

En los conjuntos de datos que tienen una gran cantidad de columnas, es aún mejor ver cuántas columnas contienen valores nulos y cuántas no.

print("No. of columns containing null values")
print(len(df.columns[df.isna().any()]))

print("No. of columns not containing null values")
print(len(df.columns[df.notna().all()]))

print("Total no. of columns in the dataframe")
print(len(df.columns))

Por ejemplo, en mi marco de datos contenía 82 columnas, de las cuales 19 contenían al menos un valor nulo.

Además, también puede eliminar automáticamente las columnas y filas dependiendo de cuál tenga valores más nulos.
Aquí está el código que hace esto de manera inteligente:

df = df.drop(df.columns[df.isna().sum()>len(df.columns)],axis = 1)
df = df.dropna(axis = 0).reset_index(drop=True)

Nota: el código anterior elimina todos sus valores nulos. Si desea valores nulos, procéselos antes.

Pradeep Singh
fuente
Hay otra pregunta enlace
Pradeep Singh
0

Se puede agregar en ese '&' se puede usar para agregar condiciones adicionales, por ejemplo

df = df[(df.EPS > 2.0) & (df.EPS <4.0)]

Tenga en cuenta que al evaluar las declaraciones, los pandas necesitan paréntesis.

David
fuente
2
Lo siento, pero OP quiere algo más. Por cierto, su código es incorrecto, regrese ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Necesita agregar paréntesis df = df[(df.EPS > 2.0) & (df.EPS <4.0)], pero tampoco es una respuesta para esta pregunta.
Israel
-1

Por alguna razón, ninguna de las respuestas enviadas anteriormente funcionó para mí. Esta solución básica hizo:

df = df[df.EPS >= 0]

Aunque, por supuesto, eso también eliminará filas con números negativos. Entonces, si quieres esos, probablemente también sea inteligente agregar esto después.

df = df[df.EPS <= 0]
samthebrand
fuente
Esto hace algo completamente diferente, ¿no?
AMC
-1

Una de las soluciones puede ser

df = df[df.isnull().sum(axis=1) <= Cutoff Value]

Otra forma puede ser

df= df.dropna(thresh=(df.shape[1] - Cutoff_value))

Espero que sean útiles.

Amit Gupta
fuente