在Pandas中查询NaN和其他名称

112 投票
7 回答
114789 浏览
提问于 2025-04-29 07:57

假设我有一个数据表 df,里面有一列叫 value,这列里有一些浮点数值,还有一些是 NaN(表示缺失值)。我想用查询语法找出数据表中那些是 NaN 的部分,应该怎么做呢?

比如,下面这个方法就不行:

df.query( '(value < 10) or (value == NaN)' )

我得到的错误是 name NaN is not defined(用 df.query('value ==NaN') 也是一样的错误)。

一般来说,有没有办法在查询中使用像 infnanpie 这些 numpy 的名称呢?

暂无标签

7 个回答

12

Pandas在处理数据表时,会用NumPy的nan值来填充空白单元格。结果就是,这种空值有一些奇怪的特性。首先,什么都不等于这种空值,连它自己也不例外。因此,你不能通过检查某个特定的相等性来寻找它。

In : 'nan' == np.nan
Out: False

In : None == np.nan
Out: False

In : np.nan == np.nan
Out: False

不过,由于一个包含np.nan值的单元格不会等于任何东西,包括另一个np.nan值,我们可以检查它是否不等于它自己。

In : np.nan != np.nan
Out: True

你可以利用这个特性,使用Pandas的查询方法,简单地搜索那些在特定列中值不等于它自己的单元格。

df.query('a != a')

或者

df[df['a'] != df['a']]
41

对于那些value不为空的行

df.query("value == value")

对于那些value为空的行

df.query("value != value")
54

你可以使用 isnanotna 这两个方法,它们简单易懂,使用起来也很方便。

import pandas as pd
import numpy as np

df = pd.DataFrame({'value': [3, 4, 9, 10, 11, np.nan, 12]})
available = df.query("value.notna()")
print(available)

#    value
# 0    3.0
# 1    4.0
# 2    9.0
# 3   10.0
# 4   11.0
# 6   12.0

not_available = df.query("value.isna()")
print(not_available)

#    value
# 5    NaN

如果你安装了 numexpr,那么在使用 .query 的时候需要加上 engine="python",这样才能正常工作。numexprpandas 推荐的工具,可以加快在大数据集上使用 .query 的速度。

available = df.query("value.notna()", engine="python")
print(available)

另外,你也可以使用顶层的 pd.isna 函数,只需将其作为本地变量引用。同样,如果有 numexpr,在使用时也需要加上 engine="python"

import pandas as pd
import numpy as np


df = pd.DataFrame({'value': [3, 4, 9, 10, 11, np.nan, 12]})
df.query("@pd.isna(value)")

#    value
# 5    NaN
140

根据这个回答,你可以使用:

df.query('value < 10 | value.isnull()', engine='python')

我确认过这个方法是有效的。

118

一般来说,你可以使用 @local_variable_name,所以像这样

>>> pi = np.pi; nan = np.nan
>>> df = pd.DataFrame({"value": [3,4,9,10,11,np.nan,12]})
>>> df.query("(value < 10) and (value > @pi)")
   value
1      4
2      9

是可以工作的,但 nan 这个值和它自己是不相等的,所以 value == NaN 这个判断永远会是假的。解决这个问题的一种方法是利用这个特性,使用 value != value 来检查是否是 nan。我们有

>>> df.query("(value < 10) or (value == @nan)")
   value
0      3
1      4
2      9

但是

>>> df.query("(value < 10) or (value != value)")
   value
0      3
1      4
2      9
5    NaN

撰写回答