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

1043

Tengo esto DataFramey quiero solo 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 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?

2
1062

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

df = df[df['EPS'].notna()]
7
  • 488
    Recomiendo usar en pandas.notnulllugar denp.isfiniteWes McKinney 21/11/12 a las 3:08
  • dieciséis
    ¿Hay alguna ventaja en indexar y copiar sobre soltar? Robert Muil 31/07/2015 a las 8:15
  • 10
    Crea Error: TypeError: ufunc 'isfinite' no es compatible con los tipos de entrada, y las entradas no se pudieron forzar de forma segura a ningún tipo compatible de acuerdo con la regla de conversión '' segura ''Philipp Schwarz 7/10/2016 a las 13:18
  • 5
    @ wes-mckinney podría por favor avisarme si dropna () es una mejor opción sobre pandas.notnull en este caso. Si es así, ¿por qué? stormfield 7 de septiembre de 2017 a las 11:53
  • 6
    @PhilippSchwarz Este error ocurre si la columna ( EPSen el ejemplo) contiene cadenas u otros tipos que no pueden ser digeridos por np.isfinite(). Recomiendo usar pandas.notnull()que maneje esto de manera más generosa. normanius 5 abr .18 a las 10:02
1053

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, incluso dropna(), está integrada en pandas explícitamente. Además de un rendimiento potencialmente mejorado en comparación con 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 eliminación de columnas en lugar de filas.

¡Muy útil!

5
  • 357
    también puedes usar df.dropna(subset = ['column_name']). Espero que eso le ahorre al menos a una persona los 5 segundos extra de '¿qué estoy haciendo mal?'. Excelente respuesta, +1James Tobin 18 de junio de 2014 a las 14:07
  • 11
    @JamesTobin, ¡acabo de pasar 20 minutos escribiendo una función para eso! La documentación oficial era muy críptica: "Etiquetas a lo largo de otro eje a considerar, por ejemplo, si está eliminando filas, estas serían una lista de columnas para incluir". No pude entender, lo que querían decir ...Sergey Orshanskiy 5 de septiembre de 2014 a las 23:52
  • df.dropna(subset = ['column_name'])es exactamente lo que estaba buscando! ¡Gracias! amalik2205 8 dic 2019 a las 21:09
  • Esta respuesta es muy útil, pero en caso de que no esté claro para cualquiera que lea qué opciones son útiles en qué situaciones, he creado una publicación de preguntas frecuentes de dropna aquí . Espero que esto ayude a las personas que están luchando para aplicar dropnaa sus necesidades específicas. cs95 18/06/20 a las 21:19
  • +1 en esta respuesta también parece ayudar a evitar tener SettingWithCopyWarningmás tarde cuando usadf.dropna(subset = ['column_name'], inplace=True)cookiemonster 2 de julio a las 17:45
131

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

import pandas as pd
df = df[pd.notnull(df['EPS'])]
5
  • 11
    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 23/04/2014 a las 12:53
  • 2
    notnulles también lo que Wes (autor de Pandas) sugirió en su comentario sobre otra respuesta. fantabolous 9 de julio de 2014 a las 3:24
  • Esta quizás sea una pregunta de novato. Pero cuando hago un df [pd.notnull (...) o df.dropna, el índice se elimina. Entonces, si hubiera 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 4 de marzo de 2016 a las 6:03
  • también puede hacer df[pd.notnull(df[df.columns[INDEX]])]dónde INDEXestaría la columna numerada si no sabe el nombreocean800 31 oct 2019 a las 20:30
  • Por alguna razón, esta respuesta funcionó para mí y no df.dropna(subset=['column name']lo hizo. Mian Asbat Ahmad 24/06/20 a las 12:42
80

Puedes usar esto:

df.dropna(subset=['EPS'], how='all', inplace=True)
1
  • 22
    how='all'es redundante aquí, porque subconjunta el marco de datos solo con un campo, por lo que ambos 'all'y 'any'tendrán el mismo efecto. Anton Protopopov 16 de enero de 2018 a las 12:41
40

La más simple de todas las soluciones:

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

The above solution is way better than using np.isfinite()

30

How to drop rows of Pandas DataFrame whose value in a certain column is NaN

Esta es una vieja pregunta que ha sido golpeada hasta la muerte, pero creo que hay más información útil que puede surgir en este hilo. Siga leyendo si está buscando la respuesta a alguna de las siguientes preguntas:

  • ¿Puedo eliminar filas si alguno de sus valores tiene NaN? ¿Y si todos son NaN?
  • ¿Solo puedo ver los NaN en columnas específicas al eliminar filas?
  • ¿Puedo eliminar filas con un recuento específico de valores de NaN?
  • ¿Cómo suelto columnas en lugar de filas?
  • Probé todas las opciones anteriores, ¡pero mi DataFrame simplemente no se actualiza!

DataFrame.dropna: Uso y ejemplos

Ya se ha dicho que df.dropnaes el método canónico para eliminar NaN de DataFrames, pero no hay nada como algunas señales visuales para ayudar en el camino.

# Setup
df = pd.DataFrame({
    'A': [np.nan, 2, 3, 4],  
    'B': [np.nan, np.nan, 2, 3], 
    'C': [np.nan]*3 + [3]}) 

df                      
     A    B    C
0  NaN  NaN  NaN
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

A continuación se muestra un detalle de los argumentos más importantes y cómo funcionan, organizados en un formato de preguntas frecuentes.


¿Puedo eliminar filas si alguno de sus valores tiene NaN? ¿Y si todos son NaN?

Aquí es donde el how=...argumento resulta útil. Puede ser uno de

  • 'any' (predeterminado): elimina filas si al menos una columna tiene NaN
  • 'all' - elimina filas solo si todas sus columnas tienen NaN

<! _ ->

# Removes all but the last row since there are no NaNs 
df.dropna()

     A    B    C
3  4.0  3.0  3.0

# Removes the first row only
df.dropna(how='all')

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

Note
If you just want to see which rows are null (IOW, if you want a boolean mask of rows), use isna:

df.isna()

       A      B      C
0   True   True   True
1  False   True   True
2  False  False   True
3  False  False  False

df.isna().any(axis=1)

0     True
1     True
2     True
3    False
dtype: bool

To get the inversion of this result, use notna instead.


¿Solo puedo ver los NaN en columnas específicas al eliminar filas?

Este es un caso de uso para el subset=[...]argumento.

Especifique una lista de columnas (o índices con axis=1) para decirles a los pandas que solo desea ver estas columnas (o filas con axis=1) al soltar filas (o columnas con axis=1.

# Drop all rows with NaNs in A
df.dropna(subset=['A'])

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

# Drop all rows with NaNs in A OR B
df.dropna(subset=['A', 'B'])

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

¿Puedo eliminar filas con un recuento específico de valores de NaN?

Este es un caso de uso para el thresh=...argumento. Especifique el número mínimo de valores NON-NULL como un número entero.

df.dropna(thresh=1)  

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

df.dropna(thresh=2)

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

df.dropna(thresh=3)

     A    B    C
3  4.0  3.0  3.0

Lo que debe tener en cuenta aquí es que debe especificar cuántos valores NON-NULL desea mantener , en lugar de cuántos valores NULL desea eliminar . Este es un punto de dolor para los nuevos usuarios.

Afortunadamente, la solución es fácil: si tiene un recuento de valores NULL, simplemente réstelo del tamaño de la columna para obtener el argumento de umbral correcto para la función.

required_min_null_values_to_drop = 2 # drop rows with at least 2 NaN
df.dropna(thresh=df.shape[1] - required_min_null_values_to_drop + 1)

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

¿Cómo suelto columnas en lugar de filas?

Utilice el axis=...argumento, puede ser axis=0o axis=1.

Le dice a la función si desea quitar filas ( axis=0) o quitar columnas ( axis=1).

df.dropna()

     A    B    C
3  4.0  3.0  3.0

# All columns have rows, so the result is empty.
df.dropna(axis=1)

Empty DataFrame
Columns: []
Index: [0, 1, 2, 3]

# Here's a different example requiring the column to have all NaN rows
# to be dropped. In this case no columns satisfy the condition.
df.dropna(axis=1, how='all')

     A    B    C
0  NaN  NaN  NaN
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

# Here's a different example requiring a column to have at least 2 NON-NULL
# values. Column C has less than 2 NON-NULL values, so it should be dropped.
df.dropna(axis=1, thresh=2)

     A    B
0  NaN  NaN
1  2.0  NaN
2  3.0  2.0
3  4.0  3.0

Probé todas las opciones anteriores, ¡pero mi DataFrame simplemente no se actualiza!

dropna, como la mayoría de las otras funciones en la API de pandas, devuelve un nuevo DataFrame (una copia del original con cambios) como resultado, por lo que debe asignarlo nuevamente si desea ver cambios.

df.dropna(...) # wrong
df.dropna(..., inplace=True) # right, but not recommended
df = df.dropna(...) # right

Referencia

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html

DataFrame.dropna(
    self, axis=0, how='any', thresh=None, subset=None, inplace=False)

enter image description here

25

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
0
23

Manera sencilla y facil

df.dropna(subset=['EPS'],inplace=True)

fuente: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html

2
  • inplace=Truees un tema extraño y no tiene ningún efecto sobre DataFrame.dropna(). Ver: github.com/pandas-dev/pandas/issues/16529AMC 16 feb.20 a las 3:56
  • 2
    ¿En qué se diferencia esta respuesta de la respuesta de @ Joe? Además, en su lugar se desaprobará eventualmente, es mejor no usarlo en absoluto. misantroop 28/03/20 a las 7:28
13

otra solución más 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
4

Otra version:

df[~df['EPS'].isna()]
1
  • ¿Por qué usar esto Series.notna()? AMC 16 feb.20 a las 3:58
1

Se puede agregar en ese '&' se puede usar para agregar condiciones adicionales, p. Ej.

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

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

1
  • 2
    Lo siento, pero OP quiere algo más. Por cierto, tu código es incorrecto, regresa 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 la respuesta para esta pregunta. jezrael 16 de marzo de 2016 a las 11:52
1

En 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 columnas y filas dependiendo de cuál tenga más valores
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.

1