Если добавить _metadata к пользовательскому подклассу Series, то при выборке по индексам теряется имя последовательности
pandas 2.2.3
Рассмотрим два варианта определения пользовательского подтипа pandas.Series, где в первом нет добавленных пользовательских свойств, а во втором есть:
import pandas as pd
class MySeries(pd.Series):
@property
def _constructor(self):
return MySeries
seq = MySeries([*'abc'], name='data')
print(f'''Case without _metadata:
{isinstance(seq[0:1], MySeries) = }
{isinstance(seq[[0, 1]], MySeries) = }
{seq[0:1].name = }
{seq[[0, 1]].name = }
''')
class MySeries(pd.Series):
_metadata = ['property']
@property
def _constructor(self):
return MySeries
seq = MySeries([*'abc'], name='data')
seq.property = 'MyProperty'
print(f'''Case with defined _metadata:
{isinstance(seq[0:1], MySeries) = }
{isinstance(seq[[0, 1]], MySeries) = }
{seq[0:1].name = }
{seq[[0, 1]].name = }
{getattr(seq[0:1], 'property', 'NA') = }
{getattr(seq[[0, 1]], 'property', 'NA') = }
''')
Результат будет следующим:
Case without _metadata:
isinstance(seq[0:1], MySeries) = True
isinstance(seq[[0, 1]], MySeries) = True
seq[0:1].name = 'data'
seq[[0, 1]].name = 'data'
Case with defined _metadata:
isinstance(seq[0:1], MySeries) = True
isinstance(seq[[0, 1]], MySeries) = True
seq[0:1].name = 'data'
seq[[0, 1]].name = None <<< Проблемный результат извлечения по индексам
getattr(seq[0:1], 'property', 'NA') = 'MyProperty'
getattr(seq[[0, 1]], 'property', 'NA') = 'MyProperty'
То есть, если добавить _metadata, то при извлечении по срезу имя последовательности сохраняется, а при извлечении по индексу - теряется, тогда как без _metadata имя сохраняется в обоих случаях.
Что нужно сделать, чтобы имя пользовательской последовательности с добавленными метаданными сохранялось?
Ответы (1 шт):
Атрибут name объекта типа Series - это дескриптор, работающий со строковым атрибутом '_name'. При этом имя '_name' по умолчанию включается в _metadata, если последнее не было переопределено пользователем. Благодаря этому имя сохраняется при модификации объекта. Следовательно, при переопределении _metadata необходимо самостоятельно добавить туда '_name' наряду с пользовательскими свойствами:
import pandas as pd
class MySeries(pd.Series):
_metadata = ['my_property', '_name']
@property
def _constructor(self):
return MySeries
seq = MySeries([*'abc'], name='data')
print(f'{seq[0:1].name = }')
print(f'{seq[[0, 1]].name = }')
# Output:
# seq[0:1].name = 'data'
# seq[[0, 1]].name = 'data'