如何删除某些列中的值为NaN的Pandas DataFrame行

big*_*bug 661 python nan dataframe pandas

我有一个DataFrame:

>>> 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
Run Code Online (Sandbox Code Playgroud)

然后我只想要那些EPS不是NaN,df.drop(....)即将返回数据帧的记录,如下所示:

                  STK_ID  EPS  cash
STK_ID RPT_Date                   
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN
Run Code Online (Sandbox Code Playgroud)

我怎么做?

Ama*_*man 823

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

......还考虑了Wouter在其原始评论中提出的解决方案.处理丢失数据的能力,包括dropna(),明确地内置到pandas中.除了手动改进的性能之外,这些功能还提供了许多可能有用的选项.

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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

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

非常方便!

  • 你也可以使用`df.dropna(subset = ['column_name'])`.希望至少为一个人节省"我做错了什么"的额外5秒.很棒的答案,+ 1 (255认同)
  • @JamesTobin,我花了20分钟为它写了一个函数![官方文档](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html)非常神秘:"沿着其他轴的标签要考虑,例如,如果你要丢弃行这些将是列的列表,包括".我无法理解,他们的意思是什么...... (9认同)
  • +1这个答案似乎也有助于避免稍后使用“df.dropna(subset = ['column_name'], inplace=True)”时出现“SettingWithCopyWarning” (2认同)

eum*_*iro 523

不要drop.就拿行,其中EPS有限的:

import numpy as np

df = df[np.isfinite(df['EPS'])]
Run Code Online (Sandbox Code Playgroud)

  • 我建议使用`pandas.notnull`而不是`np.isfinite` (442认同)
  • 索引和复制是否有任何优势? (10认同)
  • 创建错误:TypeError:输入类型不支持ufunc'isfinite',并且输入无法根据强制转换规则"安全"安全地强制转换为任何支持的类型 (9认同)
  • 我们还可以使用 df.dropna(subset=['EPS'])` (6认同)
  • @维斯 - 麦金尼也请让我知道如果dropna()在这种情况下更好的选择了pandas.notnull?如果是这样,为什么呢? (4认同)
  • @PhilippSchwarz如果列(示例中的"EPS")包含无法被`np.isfinite()`消化的字符串或其他类型,则会发生此错误.我建议使用`pandas.notnull()`来更慷慨地处理这个问题. (4认同)
  • 如果有多个列,“dropna”实际上会更快。 (2认同)

小智 110

我知道这已经得到了解答,但仅仅是为了纯粹的熊猫解决这个具体问题的方法,而不是阿曼的一般描述(这很精彩),以防其他人发生这种情况:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Run Code Online (Sandbox Code Playgroud)

  • 实际上,具体的答案是:`df.dropna(subset = ['EPS'])`(根据Aman的一般描述,当然这也有效) (10认同)
  • "notnull"也是Wes(Pandas的作者)在他对另一个答案的评论中提出的建议. (2认同)

Joe*_*Joe 46

你可以用这个:

df.dropna(subset=['EPS'], how='all', inplace=True)
Run Code Online (Sandbox Code Playgroud)

  • `how ='all'`在这里是多余的,因为你只用一个字段对数据帧进行子集化,因此"all"和"any"都具有相同的效果. (15认同)

Gil*_*gio 30

最简单的解决方案:

filtered_df = df[df['EPS'].notnull()]
Run Code Online (Sandbox Code Playgroud)

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


cs9*_*s95 30

如何删除某列中值为 NaN 的 Pandas DataFrame 行

这是一个老问题,已经被打死了,但我相信在这个线程上有一些更有用的信息。如果您正在寻找以下任何问题的答案,请继续阅读:

  • 如果任何值具有 NaN,我可以删除行吗?如果它们都是 NaN 呢?
  • 删除行时,我可以只查看特定列中的 NaN 吗?
  • 我可以删除具有特定 NaN 值计数的行吗?
  • 如何删除列而不是行?
  • 我尝试了上述所有选项,但我的 DataFrame 无法更新!

DataFrame.dropna: 用法和例子

已经有人说这df.dropna是从 DataFrames 中删除 NaN 的规范方法,但是没有什么比一些视觉提示可以帮助的了。

# 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
Run Code Online (Sandbox Code Playgroud)

以下是最重要的参数及其工作原理的详细信息,以常见问题解答格式排列。


如果任何值具有 NaN,我可以删除行吗?如果它们都是 NaN 呢?

这就是how=...论证派上用场的地方。它可以是其中之一

  • 'any' (默认)- 如果至少一列包含 NaN,则删除行
  • 'all' - 仅当所有列都有 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
Run Code Online (Sandbox Code Playgroud)

注意
如果您只想查看哪些行为空(IOW,如果您想要行的布尔掩码),请使用 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
Run Code Online (Sandbox Code Playgroud)

要获得此结果的反转,请 notna 改用。


删除行时,我可以只查看特定列中的 NaN 吗?

这是subset=[...]参数的一个用例。

指定一个列(或带有 的索引axis=1)的列表,以告诉 Pandasaxis=1在删除行(或带有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
Run Code Online (Sandbox Code Playgroud)

我可以删除具有特定 NaN 值计数的行吗?

这是thresh=...参数的一个用例。将非空值的最小数量指定为整数。

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
Run Code Online (Sandbox Code Playgroud)

这里要注意的是,您需要指定要保留多少个非空值,而不是要删除多少个 NULL 值。这是新用户的痛点。

幸运的是,修复很简单:如果您有 NULL 值的计数,只需从列大小中减去它即可获得该函数的正确 thresh 参数。

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
Run Code Online (Sandbox Code Playgroud)

如何删除列而不是行?

使用axis=...参数,它可以是axis=0axis=1

告诉函数是要删除行 ( axis=0) 还是删除列 ( 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
Run Code Online (Sandbox Code Playgroud)

我尝试了上述所有选项,但我的 DataFrame 无法更新!

dropna,就像 Pandas API 中的大多数其他函数一样,返回一个新的 DataFrame(带有更改的原始副本)作为结果,因此如果您想查看更改,您应该将其分配回来。

df.dropna(...) # wrong
df.dropna(..., inplace=True) # right, but not recommended
df = df.dropna(...) # right
Run Code Online (Sandbox Code Playgroud)

参考

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)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


Ant*_*pov 21

你可以使用datan方法notnullisnull的反转,或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
Run Code Online (Sandbox Code Playgroud)


Nur*_*aaz 11

简单方法

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

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

  • 这个答案与@Joe 的答案有何不同?另外,inplace 最终会被弃用,最好根本不要使用它。 (2认同)

Max*_*axU 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
Run Code Online (Sandbox Code Playgroud)