2015-09-01 61 views
0

在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 

好了,所以我一直在愉快地这样做了虽然,但是最近我遇到了不支持这个的熊猫的一部分。具体来说,使用自定义列标签的DataFrame上的方法to_hdf/read_hdfwill fail。这对我来说不是一个破坏者。我可以使用咸菜而不是HDF5来减少一些效率。

但是更大的问题是,大熊猫一般是否支持自定义对象作为列标签?换句话说,我是否应该继续以这种方式使用熊猫,否则将来会在大熊猫的其他部分(除了HDF5)中破碎,给我带来未来的痛苦?

PS。作为一个方面说明,如果您目前还没有使用自定义对象作为列标签,我也不介意如何解决上述示例中列特定信息的问题,如fmt_fn

+0

有趣的问题,因为我从来没有见过在一个数据帧列传递的对象。我会建议不要这样使用。如果您需要灵活性,您可以保留一个字段名称和底层对象的字典。 – Alexander

+0

这将是糟糕的设计(海事组织)保持每个DataFrame单独的数据结构并行于'foo.columns',而不是简单地将列专用数据放入'foo.columns'。我只会在必要时这样做,即,如果Pandas真的不支持自定义对象作为列标签。因此我发布了这个问题。 – aiai

+0

数据框的列只是一个索引。看来唯一的要求是对象是可散列的。 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Index.html – Alexander

回答

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 
+0

正如我在我的问题文章中指出的那样,'fmt_fn'只是列特定数据的例子。我的实际列标签对象要复杂得多,比输出格式提供更丰富的功能。 – aiai

+0

至于你列出的“最大的两个问题”:(a)序列化是我碰到的一个问题,促使我写这个问题 - 希望我能用腌菜来处理它。 (b)“不能再做'df ['time']'”在我的书中不会被认为是一个问题,因为'time'不是列标签对象(仅仅是它的打印表示) - 正确的代码是'df [sec_col]'并且按预期正常工作。 考虑到您的意见和Alexander的评论,我认为我目前的结论是继续在列标签中使用自定义对象是安全的。谢谢! – aiai

相关问题