У меня следующая схема DataFrame
:
|str_A |str_B |co_A |co_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
работают, другие нет.
Я подумал, что это может быть причиной смешанных типов, и поэтому я отбросилСтроковые значения и оставили только пользовательские объекты, ошибка сохраняется.Я ничего не понимаю здесь, и я был бы признателен за любую помощь.
EDIT : Я использую панды версии 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, CustomObject
класс импортирован из библиотеки.
Я создал еще один простой класс непосредственно в jupyter, используя методы, аналогичные оригинальным, чтобы проверить, что с данными что-то не так ... и это сработало.Что еще более запутанно.Должно быть что-то не так с классом CustomObject (я не писал этот класс, однако не могу найти ничего, что могло бы вызвать проблему).
Класс должен обрабатывать сравнения версий -Спецификация может быть найдена в сущности 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__()
Работает, как и ожидалось, без комментированного кода выше.