Pandas是否允许自定义对象作为列标签?

时间:2015-09-01 20:47:00

标签: python pandas

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

In [100]: class Col:
     ...:     def __init__(self, name, fmt_fn):
     ...:         self.name = name
     ...:         self.fmt_fn = fmt_fn
     ...:     def __str__(self):
     ...:         return self.name
     ...:     

In [101]: sec_col = Col('time', lambda val: str(timedelta(seconds=val)).split('.')[0])

In [102]: dollar_col = Col('money', lambda val: '${:.2f}'.format(val))

In [103]: foo = pd.DataFrame(np.random.random((3, 2)) * 1000, columns = [sec_col, dollar_col])

In [104]: print(foo)  # ugly
         time       money
0  773.181402  720.997051
1   33.779925  317.957813
2  590.750129  416.293245

In [105]: print(foo.to_string(formatters = [col.fmt_fn for col in foo.columns]))  # pretty
     time   money
0 0:12:53 $721.00
1 0:00:33 $317.96
2 0:09:50 $416.29

好的,所以我很乐意这样做一段时间,但后来我最近遇到了一部分不支持这种情况的Pandas。具体而言,具有自定义列标签的DataFrame上的方法to_hdf / read_hdf will fail。这对我来说不是一个破坏者。我可以使用泡菜而不是HDF5而失去一些效率。

但更大的问题是,Pandas一般是否支持自定义对象作为列标签?换句话说,我应该继续以这种方式使用Pandas,还是将来会在Pandas的其他部分(除了HDF5)中断,这会让我后来感到痛苦?

PS。作为旁注,如果您当前没有使用自定义对象作为列,我也不介意您是否也在讨论如何解决列特定信息的问题,例如上例中的fmt_fn标签。

2 个答案:

答案 0 :(得分:0)

现在,DataFrame格式化的细粒度控制真的不可能。例如,有关可能性的讨论,请参见herehere。我确信一个经过深思熟虑的API(和PR!)会很受欢迎。

在将自定义对象用作列时,两个最大的问题可能是序列化和索引语义(例如,不能再进行df['time'])。

一种可能的解决方法是将DataFrame包装成某种漂亮的印刷结构,如下所示:

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

答案 1 :(得分:0)

自发布以来已经有五年了,所以我希望这对某人还是有帮助的。我设法建立了一个对象来保存pandas数据框列的元数据,但仍然可以作为常规列访问(对我来说似乎如此)。下面的代码只是涉及此内容的整个类的一部分。

__ repr用于在打印数据框而不是对象时显示对象的名称

__ eq用于将请求的名称检查为对象的可用名称__hash在此过程中也被使用,因为列名的工作方式类似于字典,所以它们必须是可哈希的。

那可能不是描述它的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)