【问题标题】:pandas sort_values throws ValueError: Categorical categories must be uniquepandas sort_values 抛出 ValueError:分类类别必须是唯一的
【发布时间】:2018-06-05 21:13:39
【问题描述】:

我有以下DataFrame 架构:

| str_A | str_B | co_A |合作_B | ... | co_X |

其中co_A 和co_B 代表自定义对象


那些对象继承object,并定义了丰富的比较方法

FWIW:__hash__ 方法也被覆盖并调用 super().__hash__()


我想做的是按两个自定义列排序,这就是混淆的地方。

以下代码按预期工作:

df.sort_values(by=['str_A', 'str_B'])

以下代码也可以:

df.sort_values(by=['co_A'])


但不起作用的是:

df.sort_values(by=['co_A', 'co_B'])

抛出

ValueError:分类类别必须是唯一的

事实证明,co_x 和 str_x 的某些组合有效,而另一些则无效。


我认为这可能是混合类型的原因,所以我删除了字符串值并只留下了自定义对象,错误仍然存​​在。我在这里一无所知,如果有任何帮助,我将不胜感激。


编辑:我使用的是熊猫版本 0.23.0

要生成可以重现问题的简单数据,可以使用以下示例代码

def feed():
    return type('Feed', (), {
        attr: names.get_first_name() if attr.startswith('substr') else names.get_last_name()
        for attr in CPE_VERSION_ATTRIBUTE_LIST
    })

feed = [feed() for i in range(100)]

EDIT2:

我使用的是 jupyter notebook,CustomObject 类是从库中导入的。

我所做的是我直接在 jupyter 中创建了另一个简单的类,使用与原始类类似的方法来检查数据是否有问题...... 并且它有效。这更令人困惑。 CustomObject 类一定有问题(我没有写这个类,但是我找不到任何可能导致问题的东西)。

该类应该处理版本比较——规范可以在 gist 中找到 https://gist.github.com/CermakM/011f17e91ffe9efbe35f29738fb23ec2

EDIT3:找到问题的根本原因,还不知道如何解决

已经实现了 CustomObject 之类的

class CustomObject:

    def __init__(self, stream: str):
        if stream is None:
            raise TypeError()

        self.stream = stream

    def __repr__(self):
        return "{cls!s}(stream={stream!r})".format(
            cls=self.__class__.__name__,
            stream=self.stream
        )

    def __str__(self):
        return "{stream!s}".format(
            stream=self.stream
        )

    def __lt__(self, other):
        if other is None:
            return False

        return self.stream < other.stream

    def __gt__(self, other):
        if other is None:
            return True

        return self.stream > other.stream

    # <<<<<<< This causes the issue 
    #     def __eq__(self, other):
    #         if other is None:
    #             return False

    #         return self.stream == other.stream
    # =======

    def __hash__(self):
        return super().__hash__()

没有上面注释的代码,它可以按预期工作。

【问题讨论】:

  • 你使用的是 pandas 0.23.0 吗?
  • 你能提供一些数据来证明这个问题吗?
  • 将这些信息添加到我的问题中,感谢您的注释。

标签: python python-3.x pandas dataframe


【解决方案1】:

这是一个老问题,但我遇到了同样的问题。

原因

问题在于,当两个对象相等时(由您的 __eq__ 函数定义),您的 __hash__ 函数应该始终返回 True。

现在情况并非如此,因为您的等价性基于 stream 属性,而您的类使用 object 的 __hash__ 函数,该函数(我相信)基于内存中的对象位置。

解决方案

如下定义散列函数可能会奏效。

def __hash__(self):
    return hash(self.stream)

【讨论】:

  • 感谢您的评论!以为它已经死了..是的,我很难找到它。我认为我可以将等价与散列函数分开定义。也就是说,哈希可能不相等,但对象将通过 == 符号进行比较。这显然是错误的假设。 比较相等的可散列对象必须具有相同的散列值。这里的问题是散列在对象生命周期内不能改变,stream 属性会改变,所以我不能使用你的解决方案。
猜你喜欢
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
  • 2019-03-26
  • 2016-08-21
  • 2016-05-03
  • 1970-01-01
  • 2017-04-08
  • 2021-12-10
相关资源
最近更新 更多