数据类型比较:在“object”数据类型下,“==”和“isin”产生不同的结果。

4

简单示例:

df = pd.DataFrame({'x': ['a', 'b', 'c'], 'y': [1, 2, 3], 'z': ['d', 'e', 'f']})
df

   x  y  z
0  a  1  d
1  b  2  e
2  c  3  f

df.dtypes

x    object
y     int64
z    object
dtype: object

思路是过滤掉“object”类型的列。我知道可以使用“select_dtypes”来实现,但提出这个问题的动机是为了研究下面要展示的奇怪行为。
“==”(因此,“.eq”)用于比较特定类型。
df.dtypes == object

x     True
y    False
z     True
dtype: bool

然而,isin并不具备以下功能:
df.dtypes.isin([object])
df.dtypes.isin(['object'])

x    False
y    False
z    False
dtype: bool

然而,创建一个np.dtype对象并传递它确实可以实现。

df.dtypes.isin([np.dtype('O')])

x     True
y    False
z     True
dtype: bool

np.isin 在这里能够正常工作,因此它没有任何不同的行为。

np.isin(df.dtypes, object)
array([ True, False,  True])

np.isin(df.dtypes, 'object')
array([ True, False,  True])

isin 在仅检查对象类型时似乎会出现问题。 df.dtypes.isin(['int']) 返回预期的结果。

顺便说一下,我在0.24上运行这些测试。

pd.__version__
'0.24.2'

这是一个bug还是预期行为?

1
@QuangHoang 显然不在0.24中。这个问题是因为我无法在聊天中重现0.20.3而产生的。 - roganjosh
这在'0.24.2'版本中对我有效。 - G. Anderson
@G.Anderson,0.24.2版本在我的电脑上对于isin[object]仍然给出了意外的答案。 - Quang Hoang
@QuangHoang,问题出在object数据类型上,很不幸。int似乎可以工作。我写帖子时才意识到这一点。 - cs95
很奇怪,对我来说两个都不起作用。@G.Anderson - Erfan
显示剩余13条评论
1个回答

7
这归结于 pandas.Series.isin 依赖哈希表 在这种情况下,而在0.20.3中,这可能会采用不同的代码路径并使用np.in1d取决于您的python / numpy版本
请注意,np.dtype('O')object的哈希值是不同的,这解释了当前失败的原因:
In [2]: hash(np.dtype('O'))
Out[2]: 7065344498483383396

In [3]: hash(object)
Out[3]: 108607961

看起来np.in1d正在对对象进行直接相等比较,并且与object/'object'的相等性内置于np.dtype('O')的定义中,独立于哈希值。
这也说明了对于pandas的isin存在一个更大的问题:相互比较相等但具有不同哈希值的对象将在小输入情况下失败。考虑以下类:
class Foo(object):
    def __init__(self, hash_val):
        self.hash_val = hash_val

    def __hash__(self):
        return self.hash_val

    def __eq__(self, other):
        return isinstance(other, Foo)

然后我们得到:
In [5]: s = pd.Series([Foo(0), Foo(1), Foo(2)])

In [6]: s == Foo(3)
Out[6]:
0    True
1    True
2    True
dtype: bool

In [7]: s.isin([Foo(3)])
Out[7]:
0    False
1    False
2    False
dtype: bool

In [8]: np.in1d(s.values, [Foo(3)])
Out[8]: array([ True,  True,  True])

这是一个bug吗?可能是,但我猜想这将是一个低优先级的修复项目,因为这是一个比较特殊的情况,很可能在性能方面不容易修复(即当前实现有一条注释指出不应将对象数据类型传递给np.in1d,因为它可能会引发错误,因此简单地委托给np.in1d是行不通的)。


3
“dtype”的比较方式非常混乱,不应该表现出它目前的行为,但如果NumPy开发人员尝试更改它,太多现有的代码将会崩溃。正如本案例所示,依赖于“dtype”与不是“numpy.dtype”实例的对象进行比较是一个坏主意。 - user2357112
FYI,2020年有关这个问题提出了一个问题:数据框dtype.isin()中的不一致性 - 我在相同代码的不同运行中出现了不一致。 - undefined

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