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

2024-11-28 08:37:00
admin
原创
191
摘要:问题描述:我有这个 DataFrame 并且只想要 EPS 列不是 NaN 的记录: STK_ID EPS cash STK_ID RPT_Date 601166 20111231 601166 NaN NaN 600036 2...

问题描述:

我有这个 DataFrame 并且只想要 EPS 列不是 NaN 的记录:

                 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

我该如何做?


解决方案 1:

不要删除,只取 EPS 不为 NA 的行:

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

解决方案 2:

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

...还请考虑 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

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),包括删除列而不是行。

非常方便!

解决方案 3:

你可以使用这个:

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

解决方案 4:

我知道这个问题已经得到解答了,但只是为了对这个特定问题进行纯粹的熊猫解决方案,而不是 Aman 的一般描述(非常棒),以防其他人遇到这个问题:

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

解决方案 5:

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

这是一个老问题,已经被讨论得烂透了,但我相信这个帖子里会浮现出一些更有用的信息。如果您正在寻找以下任何问题的答案,请继续阅读:

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

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


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

注意

如果您只是想查看哪些行为空(换句话说,如果您想要行的布尔掩码),请使用
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=[...]

指定列(或带有 的索引)的列表以告诉 Pandas在删除行(axis=1或带有 的列)时只想查看这些列(或带有 的行) 。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=...。将非空值的最小数量指定为整数。

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

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

幸运的是,修复很容易:如果您有 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)

在此处输入图片描述

解决方案 6:

最简单的解决方案:

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

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

解决方案 7:

簡單易行的方法

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

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

解决方案 8:

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

解决方案 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()]

解决方案 11:

以下方法对我有用。如果以上方法都不起作用,则此方法会有所帮助:

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

基本思想是,只有长度强度大于 1 时,才选取记录。如果你正在处理字符串数据,这尤其有用

最好的!

解决方案 12:

可以添加“&”来添加附加条件,例如

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

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

解决方案 13:

您也可以使用notna内部query

In [4]: df.query('EPS.notna().values')
Out[4]: 
                 STK_ID.1  EPS  cash
STK_ID RPT_Date                     
600016 20111231    600016  4.3   NaN
601939 20111231    601939  2.5   NaN

解决方案 14:

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

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)

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

解决方案 15:

那些想要将 dropna 作为特征工程/ scikit-learn 流程的一部分的人可以使用DropMissingDataFeature-engine。

下面的操作将删除数据框中所有带有 nan 的行:

import pandas as pd
import numpy as np
from feature_engine.imputation import DropMissingData
X = pd.DataFrame(dict(
       x1 = [np.nan,1,1,0,np.nan],
       x2 = ["a", np.nan, "b", np.nan, "a"],
       ))
dmd = DropMissingData()
dmd.fit(X)
dmd.transform(X)

前一个块的结果是:

    x1 x2
2  1.0  b

仅在特定列中删除带有 nan 的行,例如 x2:

dmd = DropMissingData(variables = "x2")
dmd.fit(X)
dmd.transform(X)

前一个块返回以下内容:

    x1 x2
0  NaN  a
2  1.0  b
4  NaN  a

最后,从管道内部:

from sklearn.linear_model import Lasso
from sklearn.preprocessing import OrdinalEncoder

from feature_engine.imputation import DropMissingData
from feature_engine.pipeline import Pipeline

pipe = Pipeline(
    [
        ("drop", DropMissingData()),
        ("enc", OrdinalEncoder()),
        ("lasso", Lasso(random_state=10)),
    ]
).set_output(transform="pandas")

pipe.fit(X, y)
preds_pipe = pipe.predict(X)

更多详细信息请参阅 Feature-engine 的dropna文档

解决方案 16:

dropnavs 布尔索引

如果我们查看源代码,在底层,dropna()正是notna()+ 布尔索引。根据传递给的内容how=all()或被any()调用以将notna掩码缩减为系列。

主要区别在于,使用,您可以指定要删除dropna()的行,而使用布尔索引,您可以指定要保留的行 ,这在逻辑上是相反的问题。因此,根据用例,从保留非 NaN 行或删除NaN 行的角度来解决删除具有 NaN 值的行的问题可能更直观。

总而言之,对于任何数据框,以下都是正确的df

df = pd.DataFrame({"A": [1, 2, pd.NA], "B": [pd.NA, 'a', 'b'], "C": [pd.NA, 10, 20]})

cols = ['A', 'B']
x1 = df.dropna(subset=cols, how='any')      # specify which rows to drop
y1 = df[df[cols].notna().all(axis=1)]       # specify which rows to keep
assert x1.equals(y1)

x2 = df.dropna(subset=cols, how='all')
y2 = df[df[cols].notna().any(axis=1)]
assert x2.equals(y2)

此外,thresh=参数相当于检查每行中非 NaN 值的数量是否不小于thresh值;换句话说,以下为 True:

thresh = 2
x3 = df[df[cols].count(axis=1) >= thresh]
y3 = df.dropna(subset=cols, thresh=thresh)
assert x3.equals(y3)

现在,如果任务只是删除具有 NaN 值的行,那么这dropna()是最直观的,应该使用。但是,由于掩码 + 布尔索引更通用,因此您可以使用它来定义更复杂的掩码和过滤器。

例如,假设您想要删除列A值为 NaN 或有多个 NaN 值的行。这需要使用 进行 2 次函数调用dropna。但是,使用布尔索引,您可以使用单个掩码进行过滤。

msk = (df.isna().sum(axis=1) > 1) | df['A'].isna()
df = df[~msk]

附注:如果您SettingWithCopyWarning在修改通过布尔索引构造的数据框时出现问题,请考虑将写时复制模式设置为 True(在此处阅读更多信息)。

pd.set_option('mode.copy_on_write', True)   # turn on copy-on-write

msk = (df.isna().sum(axis=1) > 1) | df['A'].isna()
df1 = df[~msk]
df1['new_col'] = 1                          # <--- no SettingWithCopyWarning

解决方案 17:

您可以尝试:

df['EPS'].dropna()
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用