Python pandas:将Series子类存储为DataFrame列

时间:2016-10-20 21:02:59

标签: python pandas

我想创建一个DataFrame,其中包含许多我已定义的不同的 Series子类。但是,当分配给Series时,似乎从DataFrame剥离了子类。

这是一个说明问题的玩具示例:

>>> import pandas as pd
>>> class SeriesSubclass(pd.Series):
...     @property
...     def _constructor(self):
...         return SeriesSubclass
...     def times_two(self):
...     """Method I need in this subclass."""
...         return self * 2
...
>>> subclass = SeriesSubclass([7, 8, 9])
>>> type(subclass)                   # fine
<class '__main__.SeriesSubclass'>
>>> subclass.times_two()             # fine
0    14
1    16
2    18
dtype: int64
>>>
>>> data = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=list('ABC'))
>>> data['D'] = subclass
>>> type(data['D'])                  # not good
<class 'pandas.core.series.Series'>
>>> data['D'].times_two()            # not good
Traceback (most recent call last):
    ...
AttributeError: 'Series' object has no attribute 'times_two'

我之前看到此问​​题可能已被提出#1713,但我无法辨别实际的解决方案。作为一个如此庞大的图书馆,它难以遵循各种PR,doc版本等。而且子类化机制似乎并没有像我所说的那样(this seems to be it)。

2 个答案:

答案 0 :(得分:0)

除非您还定义了自己的pd.DataFrame子类,否则我认为您运气不佳。这将是一项更艰巨的任务。

考虑这个例子

df = pd.DataFrame()
s = pd.Series([1, 2, 3])
s.random_attribute = 'hello!'
print(s.random_attribute)

df['A'] = s
print(df.A.random_attribute)

hello!
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-273-e0031d933193> in <module>()
      5 
      6 df['A'] = s
----> 7 print(df.A.random_attribute)

//anaconda/envs/3.5/lib/python3.5/site-packages/pandas/core/generic.py in __getattr__(self, name)
   2742             if name in self._info_axis:
   2743                 return self[name]
-> 2744             return object.__getattribute__(self, name)
   2745 
   2746     def __setattr__(self, name, value):

AttributeError: 'Series' object has no attribute 'random_attribute'

df.A不是sdf.As构造,并忽略它的类型。

答案 1 :(得分:0)

为了有类似需求的人的利益:我认为最好的解决方案是定义DataFrame的子类并使用__getitem__逻辑进行干预。

我原来的问题是基于假设DataFrame被实现为容器,从根本上说它不是。它更有活力,例如......

>>> from pandas import Series, DataFrame
>>> s = Series([1, 2, 3, 4], name='x')
>>> df = DataFrame(s)
>>> s is df.x
False

因此,为了将列检索为Series的子类,您需要修改__getitem__

我已在我自己的软件包中实现了这个功能,可以作为示例:https://github.com/jmackie4/activityio/blob/master/activityio/_util/types.py

我很想听到任何人提供更优雅的解决方案!