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

Posted

技术标签:

【中文标题】如何删除某一列中值为 NaN 的 Pandas DataFrame 行【英文标题】:How to drop rows of Pandas DataFrame whose value in a certain column is NaN 【发布时间】:2017-11-05 10:35:31 【问题描述】:

我有这个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

我该怎么做?

【问题讨论】:

dropna: pandas.pydata.org/pandas-docs/stable/generated/… df.dropna(subset = ['column1_name', 'column2_name', 'column3_name']) 【参考方案1】:

不要丢弃,只取EPS不NA的行:

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

【讨论】:

我建议使用pandas.notnull 而不是np.isfinite 索引和复制比删除有什么优势吗? 创建错误:TypeError: 输入类型不支持 ufunc 'isfinite',并且根据强制转换规则 ''safe'' 无法安全地将输入强制转换为任何支持的类型 @wes-mckinney 能否让我知道在这种情况下 dropna () 是否比 pandas.notnull 更好?如果是,那为什么? @PhilippSchwarz 如果列(示例中为EPS)包含np.isfinite() 无法消化的字符串或其他类型,则会发生此错误。我建议使用pandas.notnull(),它会更慷慨地处理这个问题。【参考方案2】:

这个问题已经解决了,但是……

...还要考虑 Wouter 在his original comment 中建议的解决方案。处理缺失数据的能力,包括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

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/generated/pandas.DataFrame.dropna.html 的文档),包括删除列而不是行。

非常方便!

【讨论】:

您也可以使用df.dropna(subset = ['column_name'])。希望至少可以为一个人节省额外的 5 秒“我做错了什么”。很好的答案,+1 @JamesTobin,我只花了 20 分钟为此编写了一个函数! The official documentation 非常神秘:“要考虑沿其他轴的标签,例如,如果您要删除行,这些将是要包含的列列表”。我无法理解,他们的意思...... df.dropna(subset = ['column_name']) 正是我想要的!谢谢! 这个答案非常有帮助,但如果任何人都不清楚哪些选项在哪些情况下有用,我整理了一个 dropna 常见问题解答帖子here。希望这可以帮助那些努力将dropna 应用于他们的特定需求的人。 +1 这个答案似乎也有助于避免在以后使用SettingWithCopyWarning 时使用df.dropna(subset = ['column_name'], inplace=True)【参考方案3】:

我知道这已经得到了回答,但只是为了这个特定问题的纯粹熊猫解决方案,而不是 Aman 的一般描述(这太棒了),以防其他人发生这种情况:

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

【讨论】:

其实具体的答案应该是:df.dropna(subset=['EPS'])(根据安缦的一般描述,当然也可以) notnull 也是 Wes(Pandas 的作者)在对另一个答案的评论中所建议的。 这可能是一个菜鸟问题。但是当我执行 df[pd.notnull(...) 或 df.dropna 时,索引会被删除。因此,如果在长度为 200 的 df 中的行索引 10 中有一个空值。运行 drop 函数后的数据帧的索引值从 1 到 9,然后从 11 到 200。无论如何要“重新索引”它 你也可以df[pd.notnull(df[df.columns[INDEX]])] 如果你不知道名字,INDEX 将是编号列 由于某种原因,这个答案对我有用,而 df.dropna(subset=['column name'] 没有。【参考方案4】:

你可以用这个:

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

【讨论】:

how='all' 在这里是多余的,因为您只使用一个字段对数据帧进行子集,因此'all''any' 将具有相同的效果。【参考方案5】:

最简单的解决方案:

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

上述解决方案比使用 np.isfinite() 好得多

【讨论】:

【参考方案6】:

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

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

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

DataFrame.dropna: 用法和例子

已经有人说df.dropna 是从 DataFrame 中删除 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

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


如果行的任何值包含 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

注意 如果您只想查看哪些行为空(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

要获得此结果的反转,请使用 notna 而是。


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

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

指定列列表(或带有axis=1 的索引)告诉pandas 在删除行(或带有axis=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

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

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

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

这里要注意的是你需要指定你想要保留多少个NON-NULL值,而不是你想要丢弃多少个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

如何删除列而不是行?

使用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

我尝试了上述所有选项,但我的 DataFrame 就是不会更新!

dropna,与 pandas API 中的大多数其他函数一样,会返回一个新的 DataFrame(带有更改的原始副本),因此如果您想查看更改,应该将其重新分配。

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

参考

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)

【讨论】:

【参考方案7】:

您可以使用数据帧方法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

【讨论】:

【参考方案8】:

简单易行的方法

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

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

【讨论】:

inplace=True 是一个奇怪的话题,对DataFrame.dropna() 没有影响。见:github.com/pandas-dev/pandas/issues/16529 这个答案与@Joe 的答案有何不同?此外,inplace is 最终将被弃用,最好不要使用它。【参考方案9】:

另一个解决方案使用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

【讨论】:

【参考方案10】:

另一个版本:

df[~df['EPS'].isna()]

【讨论】:

为什么在Series.notna() 上使用这个?【参考方案11】:

可以添加'&'可以用于添加附加条件,例如

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

请注意,在评估语句时,pandas 需要括号。

【讨论】:

抱歉,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 &gt; 2.0) &amp; (df.EPS &lt;4.0)],但它也不是这个问题的答案。【参考方案12】:

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

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 列至少包含一个空值。

此外,您还可以自动删除列和行,具体取决于哪个具有更多空值 这是智能执行此操作的代码:

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

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

【讨论】:

还有一个问题link 这道题真的是被挤出来的提问了,明白了吗? :)【参考方案13】:

以下方法对我有用。如果上述方法都不起作用,那将有所帮助:

df[df['colum_name'].str.len() >= 1]

基本思想是只有当长度强度大于 1 时才拾取记录。这在处理字符串数据时特别有用

最好的!

【讨论】:

以上是关于如何删除某一列中值为 NaN 的 Pandas DataFrame 行的主要内容,如果未能解决你的问题,请参考以下文章

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

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

pandas删除nan数据,筛选出nan的数据,筛选出非nan的数据,替换nan值

pandas groupby 滚动均值/中值删除缺失值

Python pandas:选择列值为null / None / nan的行[重复]

pandas如何删除指定行