You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义带_metadata的pandas Series子类,索引时如何保留序列名称?

解决pandas Series子类带自定义元数据时索引操作丢失名称的问题

在pandas 2.2.3版本中,我们定义两种pandas.Series的自定义子类变体:第一种未添加自定义属性,第二种通过_metadata指定自定义元数据。

代码示例

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         <<< Problematic result of indexing
  getattr(seq[0:1], 'property', 'NA') = 'MyProperty'  
  getattr(seq[[0, 1]], 'property', 'NA') = 'MyProperty'  

可见,定义_metadata后,切片操作可保留序列名称,但列表索引操作会丢失名称;未定义_metadata时两种操作均保留名称。

解决方案

方法1:将name加入_metadata列表

pandas在处理自定义元数据时,会自动复制_metadata中声明的属性到新实例。将name添加到_metadata中,就能确保索引操作后name属性被保留:

class MySeries(pd.Series):
    # 将name加入自定义元数据列表
    _metadata = ['property', 'name']

    @property
    def _constructor(self):
        return MySeries


seq = MySeries([*'abc'], name='data')
seq.property = 'MyProperty'

print(f'''Case with name in _metadata:
  {isinstance(seq[[0, 1]], MySeries) = }
  {seq[[0, 1]].name = }
  {getattr(seq[[0, 1]], 'property', 'NA') = }
''')

运行后输出:

Case with name in _metadata:
  isinstance(seq[[0, 1]], MySeries) = True
  seq[[0, 1]].name = 'data'
  getattr(seq[[0, 1]], 'property', 'NA') = 'MyProperty'

方法2:重写__getitem__方法手动保留名称

如果不想修改_metadata,可以重写__getitem__方法,在返回新实例时检查并设置name:

class MySeries(pd.Series):
    _metadata = ['property']

    @property
    def _constructor(self):
        return MySeries
    
    def __getitem__(self, key):
        result = super().__getitem__(key)
        # 仅当结果是MySeries实例且name为空时,继承原实例的name
        if isinstance(result, MySeries) and result.name is None:
            result.name = self.name
        return result


seq = MySeries([*'abc'], name='data')
seq.property = 'MyProperty'

print(f'''Case with overridden __getitem__:
  {isinstance(seq[[0, 1]], MySeries) = }
  {seq[[0, 1]].name = }
  {getattr(seq[[0, 1]], 'property', 'NA') = }
''')

运行后同样能得到保留name的结果。

内容的提问来源于stack exchange,提问作者vitalizzare

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:22:05