python - Pandas 列选择 : non commutative bitwise OR when selecting on str and NaN

标签 python pandas

简介:

给定一个数据框,我认为以下内容是正确的:

df[(condition_1) | (condition_2)] <=> df[(condition_2) | (condition_1)]

df[(df.col1==1) | (df.col1==2)] <=> df[(df.col1==2) | (df.col1==1)]

问题:

但事实证明它在以下情况下失败,其中涉及 NaN 这可能是它失败的原因:

df = pd.DataFrame([[np.nan, "abc", 2], ["abc", 2, 3], [np.nan, 5,6], [8,9,10]], columns=["A", "B", "C"])
df
     A    B   C
0  NaN  abc   2
1  abc    2   3
2  NaN    5   6
3    8    9  10

以下按预期工作:

df[(df.A.isnull()) | (df.A.str.startswith("a"))]
     A    B  C
0  NaN  abc  2
1  abc    2  3
2  NaN    5  6

但是如果我交换元素,我会得到不同的结果:

df[(df.A.str.startswith("a")) | (df.A.isnull())]
     A  B  C
1  abc  2  3

我认为问题来自于这种情况:

df.A.str.startswith("a")
0     NaN
1    True
2     NaN
3     NaN
Name: A, dtype: object

我用 NaN 而不是 False 的地方。

问题:

  • 这种行为是预期的吗?这是一个错误吗?因为如果没有预料到这种行为,它可能会导致潜在的数据丢失
  • 为什么它会这样(以不可交换的方式)?

更多详情:

更准确地说,让我们C1 = (df.A.str.startswith("a"))C2 = (df.A.isnull()):

与:

  C1     C2
 NaN   True
True  False
 NaN   True
 NaN  False

我们有:

C1 | C2
0    False
1     True
2    False
3    False
Name: A, dtype: bool

这里不计算 C2,NaN 变为 False。

在这里:

C2 | C1
0     True
1     True
2     True
3    False
Name: A, dtype: bool

NaN 为 False(它返回所有带 & 的 False)但两个条件都被评估。

显然:C1 | C2 != C2 | C1

只要保留交换性,我就不会介意 NaN 产生奇怪的结果,但这里有一个条件未计算。

实际上输入中的 NaN 不是问题,因为您在 B 列上有同样的问题:

(df.B.str.startswith("a")) | (df.B==2) != (df.B==2) | (df.B.str.startswith("a"))

这是因为在其他对象上应用 str 方法会返回 NaN*,如果先计算它会阻止计算第二个条件。所以主要问题仍然存在。

*(可以使用 str.startswith("a", na=False) 来选择,正如@ayhan 所注意到的)

最佳答案

经过一些研究,我相当确定这是 pandas 中的一个错误。我无法在他们的代码中找到具体原因,但我的结论是,要么完全禁止您进行比较,要么在评估 | 表达式时存在错误。您可以使用一个非常简单的示例重现该问题,即:

import numpy as np
import pandas as pd

a = pd.Series(np.nan)
b = pd.Series(True)

print( a | b )  # Gives False
print( b | a )  # Gives True

第二个结果显然是正确的。我只能猜测第一个失败的原因,因为我不了解 pandas 代码库。因此,如果我弄错了,请纠正我,或者如果您觉得这还不够回答,请告诉我。

通常,np.nan 在整个 python 中都被视为 True,您可以轻松检查:

import numpy as np
if np.nan:
    print("I am True")

这在 numpy 甚至 pandas 中也是有效的,正如您可以看到的那样:

import numpy as np
import pandas as pd
if np.all(np.array([np.nan])):
    print("I am True in numpy")
if pd.Series(np.nan).astype("bool").bool():
    print("and in pandas")

或者通过简单地执行 pd.Series([np.nan]).astype("bool")

到目前为止一切都是一致的。当您使用包含 NaNSeries 执行 | 时,现在会出现问题。还有很多其他人有类似的问题,例如这个 question或者那个blog post (不过,这是针对旧版本的)。没有人对这个问题给出满意的答案。链接问题的唯一答案实际上没有给出充分的理由,因为 | 的行为方式甚至与包含相同信息的 numpy 数组的行为方式不同。对于 numpy,np.array(np.nan) | np.array(True)np.array(np.nan) | np.array(1.0) 实际上给出了一个 TypeError,因为 np.bitwise_or 无法处理 float 。

由于行为不一致且缺少任何相关文档,我只能断定这是一个错误。作为解决方法,您可以回退到@ayhan 提出的解决方案并使用 na 参数(如果您需要的所有函数都存在该参数)。您还可以在要比较的 Series/Dataframe 上使用 .astype("bool")。但是请注意,这会将 NaN 转换为 True,因为这是通常的 python 约定(参见 answer 例如)。如果你想避免这种情况,你可以使用 .fillna(False).astype("bool"),我找到了 here .通常,应该提交一份关于 pandas 的错误报告,因为这种行为显然是不一致的!

关于python - Pandas 列选择 : non commutative bitwise OR when selecting on str and NaN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39000907/

相关文章:

python - 将 scikit-learn 向量化器和词汇表与 gensim 一起使用

python - 将计算值/差值除以先前值 -> 'slope'

python - 如何在 Matplotlib 中仅绘制一个表格?

python - 如何在python中批量读取pandas模块的read_csv()

python - 从 Pandas Dataframe 创建嵌套字典

python - 使用 pandas 从累积损益表报告中获取每个季度的增量值

python - 我可以读取使用第一列和该列作为微调器的输入而不重复的 CSV 文件吗?

java - 终端输出到变量(从 java 到 python) - 将输出放入 RAM 而不是写入文件的最佳编码实践

python - 如何连接两个对象的路径?

python - 如何在Elasticsearch中批量插入而忽略过程中可能出现的所有错误?