如何删除在特定列中的值为NaN的Pandas DataFrame行


749

我有这个DataFrame,只想要EPS列不是的记录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

...例如df.drop(....)要得到这个结果的数据框:

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

我怎么做?



176
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
osa 2014年

Answers:


652

不要丢掉,只取EPS不是NA的行:

df = df[df['EPS'].notna()]

470
我建议使用pandas.notnull而不是np.isfinite
Wes McKinney

11
索引和复制比删除有什么好处吗?
罗伯特·穆伊

9
创建错误:TypeError:输入类型不支持ufunc'isfinite',并且根据强制转换规则“ safe”,不能将输入安全地强制转换为任何受支持的类型
Philipp Schwarz

4
@ wes-mckinney请让我知道在这种情况下dropna()是否比pandas.notnull更好的选择?如果是这样,那为什么呢?
Stormfield'9

4
@PhilippSchwarz如果列(EPS在示例中)包含不能由消化的字符串或其他类型,则会发生此错误np.isfinite()。我建议使用pandas.notnull()它将更慷慨地处理此问题。
normanius

901

这个问题已经解决,但是...

...还要考虑伍特(Wouter)在其原始评论中提出的解决方案。dropna()大熊猫内置了处理丢失数据(包括)的功能。除了通过手动执行可能会提高的性能外,这些功能还带有多种可能有用的选项。

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

还有其他选项(请参见http://pandas.pydata.org/pandas-docs/stable/generation/pandas.DataFrame.dropna.html上的文档),包括删除列而不是行。

很方便!


281
您也可以使用df.dropna(subset = ['column_name'])。希望这至少可以节省一个人5秒钟的“我在做什么错”。好答案,+ 1
詹姆斯·托宾

10
@JamesTobin,我只花了20分钟编写了一个函数!官方文档非常含糊:“要考虑的其他方向的标签,例如,如果要删除行,这些将是要包括的列的列表”。我听不懂他们的意思……
osa

df.dropna(subset = ['column_name'])正是我想要的!谢谢!
amalik2205 '19

123

我知道已经回答了这个问题,但是只是为了对这个特定问题提供一个纯粹的熊猫解决方案,而不是Aman的一般性描述(这很妙),以防万一其他人发生于此:

import pandas as pd
df = df[pd.notnull(df['EPS'])]

10
实际上,具体的答案将是:(df.dropna(subset=['EPS'])基于对Aman的一般描述,这当然也可以工作)
joris

2
notnull这也是韦斯(《熊猫》的作者)在对另一个答案的评论中所建议的。
惊人的2014年

这可能是一个菜鸟问题。但是当我执行df [pd.notnull(...)或df.dropna时,索引将被删除。因此,如果行索引10的长度为200的df中存在空值。运行drop函数后的数据帧的索引值从1到9,然后从11到200。无论如何要对其“重新索引”
Aakash Gupta

你也可以做df[pd.notnull(df[df.columns[INDEX]])]在那里INDEX将是编号列,如果你不知道的名字
ocean800

60

您可以使用此:

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

18
how='all'这在这里是多余的,因为您仅用一个字段对数据帧进行了子集设置,因此两者'all''any'将具有相同的效果。
安东·普罗托波夫

35

所有解决方案中最简单的:

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

上面的解决方案比使用np.isfinite()更好


22

你可以使用数据帧的方法NOTNULL或逆ISNULL,或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


10

还有一个使用以下事实的解决方案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


2

在具有大量列的数据集中,最好查看有多少列包含空值而有多少列不包含空值。

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))

例如,在我的数据框中,它包含82列,其中19列至少包含一个空值。

此外,您还可以自动删除cols和row,具体取决于哪个具有更多的null值。
以下是巧妙地执行此操作的代码:

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

注意:上面的代码删除了所有空值。如果需要空值,请先处理它们。


还有另一个问题链接
Pradeep Singh

0

可以将其添加为'&'可用于添加其他条件,例如

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

请注意,在评估语句时,熊猫需要加上括号。


2
抱歉,OP还需要其他东西。顺便说一句,您的代码是错误的,返回ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().。您需要添加括号- df = df[(df.EPS > 2.0) & (df.EPS <4.0)],但这不是此问题的答案。
jezrael

-1

由于某种原因,以前提交的答案都对我不起作用。这个基本解决方案做到了:

df = df[df.EPS >= 0]

当然,这也会删除带有负数的行。因此,如果您想要这些,在以后添加它可能也很聪明。

df = df[df.EPS <= 0]

这是完全不同的,不是吗?
AMC

-1

解决方案之一可以是

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

另一种方法可以是

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

我希望这些是有用的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.