Python 熊猫是否允许自定义对象作为列标签?

Python 熊猫是否允许自定义对象作为列标签?,python,pandas,Python,Pandas,在Pandas中,我一直使用自定义对象作为列标签,因为它们为特定于列的信息/方法提供了丰富/灵活的功能。例如,您可以设置自定义的fmt\u fn来格式化每个列(请注意,这只是一个示例,我的实际列标签对象更复杂): 好吧,我很高兴这么做了一段时间,但最近我发现熊猫的一部分不支持这个。具体地说,在具有自定义列标签的数据帧上,方法到\u hdf/读取\u hdf。这对我来说不是一个破坏者。我可以用pickle代替HDF5,但会损失一些效率 但更大的问题是,熊猫一般支持自定义对象作为列标签吗?换句话说,

在Pandas中,我一直使用自定义对象作为列标签,因为它们为特定于列的信息/方法提供了丰富/灵活的功能。例如,您可以设置自定义的
fmt\u fn
来格式化每个列(请注意,这只是一个示例,我的实际列标签对象更复杂):

好吧,我很高兴这么做了一段时间,但最近我发现熊猫的一部分不支持这个。具体地说,在具有自定义列标签的数据帧上,方法
到\u hdf
/
读取\u hdf
。这对我来说不是一个破坏者。我可以用pickle代替HDF5,但会损失一些效率

但更大的问题是,熊猫一般支持自定义对象作为列标签吗?换句话说,我是应该继续这样使用熊猫,还是将来会在熊猫的其他部分(除了HDF5)出现这种断裂,给我带来未来的痛苦


顺便说一句,如果您当前没有使用自定义对象作为列标签,我不介意您也插话如何解决上述示例中的特定于列的信息问题,例如
fmt\fn

DataFrame
的格式进行细粒度控制目前还不太可能。例如,有关可能性的讨论,请参见或。我相信一个经过深思熟虑的API(和PR!)会受到欢迎

就使用自定义对象作为列而言,最大的两个问题可能是序列化和索引语义(例如,不能再执行
df['time']

一种可能的解决方法是将
数据框
包装成一种漂亮的打印结构,如下所示:

In [174]: class PrettyDF(object):
     ...:     def __init__(self, data, formatters):
     ...:         self.data = data
     ...:         self.formatters = formatters
     ...:     def __str__(self):
     ...:         return self.data.to_string(formatters=self.formatters)
     ...:     def __repr__(self):
     ...:         return self.__str__()


In [172]: foo = PrettyDF(df, 
                        formatters={'money': '${:.2f}'.format, 
                                    'time': lambda val: str(timedelta(seconds=val)).split('.')[0]})


In [178]: foo
Out[178]: 
     time   money
0 0:13:17 $399.29
1 0:08:48 $122.44
2 0:07:42 $491.72

In [180]: foo.data['time']
Out[180]: 
0    797.699511
1    528.155876
2    462.999224
Name: time, dtype: float64

这篇文章发表已经五年了,所以我希望这篇文章对某些人还是有帮助的。我已经成功地构建了一个对象来保存dataframe列的元数据,但仍然可以作为常规列访问(或者在我看来是这样)。下面的代码只是整个类的一部分

__如果打印的是数据帧而不是对象,则repr用于显示对象的名称

__eq用于将请求的名称检查为对象的可用名称uu散列也用于此过程列名需要是可散列的,因为它的工作原理类似于字典

这可能不是python式的描述方式,但在我看来,这就是它的工作方式

    class ColumnDescriptor:
        def __init__(self, name, **kwargs):
            self.name = name
            [self.__setattr__(n, v) for n, v in kwargs.items()]
    
        def __repr__(self): return self.name
        def __str__(self): return self.name
        def __eq__(self, other): return self.name == other
        def __hash__(self): return hash(self.name)

有趣的问题,因为我从未见过对象在数据帧中作为列传递。我建议不要使用这种用法。如果您需要灵活性,您可以保留列名和底层对象的字典。在每个数据帧中维护与
foo.columns
并行的单独数据结构,而不是简单地将特定于列的数据放入
foo.columns
,这将是一种糟糕的设计(IMO)。我只会在必要时这样做,即熊猫确实不支持自定义对象作为列标签。因此我提出了这个问题。数据框的列只是一个索引。看起来唯一的要求是对象是可散列的。正如我在问题帖中所指出的,
fmt\u fn
只是列特定数据的示例。我的实际列标签对象要复杂得多,提供了比输出格式更丰富的功能。就您列出的“两个最大的问题”而言:(a)序列化是我遇到的一个问题,这促使我写这个问题——希望我能用pickle处理它。(b) “不能再做
df['time']
”在我的书中不会被认为是一个问题,因为
'time'
不是列标签对象(仅仅是它的打印表示)——正确的代码是
df[sec_col]
,并且按照预期正确工作。考虑到您的评论和Alexander在上面的评论,我认为我目前的结论是,在列标签中继续使用自定义对象是安全的。谢谢我用
\uuu str\uuu
尝试了同样的方法,但它不适用于多索引数据帧。你也有解决办法吗?
    class ColumnDescriptor:
        def __init__(self, name, **kwargs):
            self.name = name
            [self.__setattr__(n, v) for n, v in kwargs.items()]
    
        def __repr__(self): return self.name
        def __str__(self): return self.name
        def __eq__(self, other): return self.name == other
        def __hash__(self): return hash(self.name)