在Pandas中查询NaN和其他名称

109

假设我有一个数据框df,其中一列value保存了一些浮点数和一些NaN。如何使用查询语法获取包含NaN的数据框的部分?

例如,下面的代码不起作用:

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

我得到了 name NaN未定义 的错误信息(对于 df.query('value ==NaN') 也是同样的错误)

通常情况下,是否有办法在查询中使用 numpy 的名称,例如 infnanpie 等等?

7个回答

135
根据这个答案,你可以使用:
df.query('value < 10 | value.isnull()', engine='python')

我验证它可以工作。


7
在这种情况下,engine='python'并不是必需的。 - Jakub Kukul
12
这取决于列的数据类型。对于具有本机NaN的浮点数,这是不必要的,但是对于字符串或整数列,则需要进行操作。 - Davidmh
2
脚本中的 engine = 'python' 是做什么用的? - Liz
2
它将表达式解释为Python表达式,而不是pandas表达式(numexpr)。https://pandas.pydata.org/docs/reference/api/pandas.eval.html#pandas.eval - Eric Ness

117

一般情况下,您可以使用@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 总是为 false。绕过这个问题的一种方法是利用这个事实,使用 value != value 作为 isnan 检查。我们有:

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

16
这样做应该有更好的方法……但我喜欢这个黑客方式。 - Stewbaca
1
@nan "技巧" 对于 numpy 变量(例如 nan = numpy.nan不起作用。但它可以过滤掉其他 字符串 - WestCoastProjects
4
@javadba:嗯,那一部分的全部意图就是展示(value == @nan)不起作用的原因,因为NaN不等于它本身,所以我使用了value != value的技巧。 - DSM
3
好的,我现在明白了。将value设置为value就可以排除NaN。 - WestCoastProjects
4
警告:这无法处理 pd.NA 条目(pandas 版本 1.0.3)。 - Auss

51
你可以使用isnanotna Series方法,这样做既简洁又易读。
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,需要传递engine="python"才能使其与.query一起正常工作。pandas建议使用numexpr来加速处理大型数据集时的.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

2
你的第一个示例在 Pandas 1.2.1 上返回 *** TypeError: 'Series' 对象是可变的,因此它们不能被哈希 - Keto
@Keto 感谢您的提醒!我已经更新了答案以解决这个问题。 - Jarno
2
我认为这是正确的答案 - 不过hack也很酷! - alex.pilon

40

value 不为 null 时

df.query("value == value")

value为空时,对于这些行

df.query("value != value")

3
太好了!我相信这正是帖子作者想要的。 - Veiga
这个是如何工作的解释?有点好奇。 - Dipanwita Mallick
2
@DipanwitaMallick 在 pandas/numpy 中 NaN != NaN。因此,NaN 不等于它本身。 - Vega
2
@DipanwitaMallick 我的评论可能有点短。在pandas/numpy中,NaN != NaN。因此,NaN不等于它本身。所以要检查单元格是否具有NaN值,可以检查cell_value != cell_value -> 这仅对NaN为真(3 != 3为False,但NaN != NaN为True,该查询仅返回具有True的项-> NaN)。要检查单元格是否没有NaN,您可以检查cell_value == cell_value -> 这仅对非NaN为真(3 == 3为True,但NaN == NaN为False,该查询仅返回具有True的项->非NaN)。 - Vega

11
Pandas使用NumPy的nan值填充DataFrame中的空单元格。事实证明,它具有一些有趣的属性。首先,nothing等于这种类型的null,即使它本身也是如此。因此,您无法通过检查任何特定的相等性来搜索它。
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']]

1
这解决了我的问题,谢谢。 - Coup

1
这也可行:df.query("value == 'NaN'")

这不是字符串比较吗?如果“value”是浮点数呢?对于数字列,它对我来说不起作用。 - Giorgio

-1

我认为其他答案通常会更好。在某些情况下,我的查询必须通过 eval(非常小心地使用 eval)并且下面的语法很有用。要求一个数字既小于又大于等于排除所有数字,仅剩下类似 null 的值。

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

df.query("value < 10 or (~(value < 10) and ~(value >= 10))")

1
仅提供代码的答案被认为是低质量的:请确保提供解释您的代码是如何解决问题的。如果您在帖子中添加更多信息,将有助于提问者和未来的读者。请参阅解释完全基于代码的答案 - Calos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接