Como descartar linhas do Pandas DataFrame cujo valor em uma determinada coluna é NaN

754

Eu tenho isso DataFramee quero apenas os registros cuja EPScoluna não é 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

... ou seja, algo como df.drop(....)obter esse quadro de dados resultante:

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

Como faço isso?

Grande erro
fonte
176
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
Osa

Respostas:

655

Não deixe cair, apenas pegue as linhas onde o EPS não é NA:

df = df[df['EPS'].notna()]
eumiro
fonte
470
Eu recomendo usar em pandas.notnullvez denp.isfinite
Wes McKinney
11
Existe alguma vantagem em indexar e copiar ao soltar?
Robert Muil
9
Cria erro: TypeError: ufunc 'isFinite' não suportado para os tipos de entrada, e as entradas não pôde ser forçado com segurança para qualquer tipos suportados de acordo com a regra casting '' seguro ''
Philipp Schwarz
4
@ wes-mckinney poderia me informar se dropna () é uma escolha melhor do que pandas.não, neste caso? Se sim, então por quê?
Stormfield
4
@PhilippSchwarz Este erro ocorre se a coluna ( EPSno exemplo) contiver seqüências de caracteres ou outros tipos que não podem ser digeridos np.isfinite(). Eu recomendo usar pandas.notnull()isso que irá lidar com isso de forma mais generosa.
Normanius
902

Esta questão já está resolvida, mas ...

... considere também a solução sugerida por Wouter em seu comentário original . A capacidade de lidar com dados ausentes, inclusive dropna(), é explicitamente incorporada aos pandas. Além do desempenho potencialmente aprimorado, em vez de fazê-lo manualmente, essas funções também vêm com uma variedade de opções que podem ser úteis.

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

Também existem outras opções (consulte os documentos em http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html ), incluindo a remoção de colunas em vez de linhas.

Muito útil!

Um homem
fonte
282
você também pode usar df.dropna(subset = ['column_name']). Espero que economize pelo menos uma pessoa os 5 segundos extras do que estou fazendo de errado. Ótima resposta, +1
James Tobin
10
@ JamesTobin, passei apenas 20 minutos para escrever uma função para isso! A documentação oficial era muito enigmática: "Etiquetas ao longo de outro eixo a considerar, por exemplo, se você estiver soltando linhas, seria uma lista de colunas a serem incluídas". Eu era incapaz de entender, o que significava ...
osa
df.dropna(subset = ['column_name'])é exatamente o que eu estava procurando! Obrigado!
precisa saber é o seguinte
123

Eu sei que isso já foi respondido, mas apenas por uma solução puramente panda para essa pergunta específica, em oposição à descrição geral de Aman (que foi maravilhosa) e no caso de mais alguém acontecer com isso:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Kirk Hadley
fonte
10
Na verdade, a resposta específica seria: df.dropna(subset=['EPS'])(com base na descrição geral da Aman, é claro que isso faz também o trabalho)
Joris
2
notnullé também o que Wes (autor de Pandas) sugeriu em seu comentário sobre outra resposta.
fantabolous
Esta talvez seja uma pergunta noob. Mas quando eu faço um df [pd.notnull (...) ou df.dropna, o índice é descartado. Portanto, se houvesse um valor nulo no índice de linha 10 em um df de comprimento 200. O quadro de dados após executar a função drop possui valores de índice de 1 a 9 e 11 a 200. De qualquer forma, para "re-indexar"
Aakash Gupta
você também pode fazer df[pd.notnull(df[df.columns[INDEX]])]onde INDEXseria a coluna numerada se não souber o nome
ocean800
60

Você pode usar isto:

df.dropna(subset=['EPS'], how='all', inplace=True)
Joe
fonte
18
how='all'é redundante aqui, porque você define o quadro de dados apenas com um campo para ambos 'all'e 'any'terá o mesmo efeito.
Anton Protopopov
35

Mais simples de todas as soluções:

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

A solução acima é muito melhor do que usar np.isfinite ()

Gil Baggio
fonte
22

Você pode usar o método dataframe notnull ou inverso de isnull ou 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
fonte
10

ainda outra solução que usa o fato 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
fonte
2

Outra versão:

df[~df['EPS'].isna()]
keramat
fonte
Por que usar isso de novo Series.notna()?
AMC
2

Em conjuntos de dados com grande número de colunas, é ainda melhor ver quantas colunas contêm valores nulos e quantas não.

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 exemplo, no meu dataframe, ele continha 82 colunas, das quais 19 continham pelo menos um valor nulo.

Além disso, você também pode remover automaticamente colunas e linhas, dependendo de quais possuem mais valores nulos.
Aqui está o código que faz isso de forma inteligente:

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

Nota: O código acima remove todos os seus valores nulos. Se você deseja valores nulos, processe-os antes.

Pradeep Singh
fonte
Existe um outro link de
Pradeep Singh
0

Pode ser adicionado em que '&' pode ser usado para adicionar condições adicionais, por exemplo

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

Observe que, ao avaliar as declarações, os pandas precisam de parênteses.

David
fonte
2
Desculpe, mas o OP quer outra coisa. Btw, seu código está errado, retorne ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Você precisa adicionar parênteses - df = df[(df.EPS > 2.0) & (df.EPS <4.0)], mas também não é resposta para esta pergunta.
Jezrael
-1

Por alguma razão, nenhuma das respostas enviadas anteriormente funcionou para mim. Esta solução básica fez:

df = df[df.EPS >= 0]

Embora, é claro, isso também elimine linhas com números negativos. Então, se você quiser, provavelmente também será bom adicionar isso depois.

df = df[df.EPS <= 0]
samthebrand
fonte
Isso faz algo completamente diferente, não?
AMC
-1

Uma das soluções pode ser

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

Outra maneira pode ser

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

Espero que sejam úteis.

Amit Gupta
fonte