如何继承pandas DataFrame?

Lei*_*Lei 30 python subclassing dataframe pandas

子类化pandas类似乎是一个常见的需求,但我找不到关于这个主题的参考.(似乎熊猫开发者仍在努力:https://github.com/pydata/pandas/issues/60).

关于这个主题有一些SO主题,但我希望这里有人可以提供一个更系统的帐户,目前最好的方法是将pandas.DataFrame子类化,满足两个,我认为,一般要求:

import numpy as np
import pandas as pd

class MyDF(pd.DataFrame):
    # how to subclass pandas DataFrame?
    pass

mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)  # <class '__main__.MyDF'>

# Requirement 1: Instances of MyDF, when calling standard methods of DataFrame,
# should produce instances of MyDF.
mydf_sub = mydf[['A','C']]
print type(mydf_sub)  # <class 'pandas.core.frame.DataFrame'>

# Requirement 2: Attributes attached to instances of MyDF, when calling standard 
# methods of DataFrame, should still attach to the output.
mydf.myattr = 1
mydf_cp1 = MyDF(mydf)
mydf_cp2 = mydf.copy()
print hasattr(mydf_cp1, 'myattr')  # False
print hasattr(mydf_cp2, 'myattr')  # False
Run Code Online (Sandbox Code Playgroud)

对于pandas.Series的子类化是否有任何显着差异?谢谢.

cjr*_*eds 23

现在有关于如何子类化Pandas数据结构的官方指南,其中包括DataFrame和Series.

该指南可在此处获取:http://pandas.pydata.org/pandas-docs/stable/internals.html#subclassing-pandas-data-structures

该指南提到了Geopandas项目中的这个子类DataFrame作为一个很好的例子:https://github.com/geopandas/geopandas/blob/master/geopandas/geodataframe.py

正如在HYRY的回答中,似乎有两件事你想要完成:

  1. 在类的实例上调用方法时,返回正确类型的实例(您的类型).为此,您只需添加_constructor应返回类型的属性即可.
  2. 添加将附加到对象副本的属性.为此,您需要将这些属性的名称存储在列表中,作为特殊_metadata属性.

这是一个例子:

class SubclassedDataFrame(DataFrame):
    _metadata = ['added_property']
    added_property = 1  # This will be passed to copies

    @property
    def _constructor(self):
        return SubclassedDataFrame
Run Code Online (Sandbox Code Playgroud)

  • “_metadata”是指类变量还是实例变量是不明确的。这个例子有一个类var。有人可以澄清一下“self.??”变量吗? (2认同)

HYR*_*YRY 12

对于要求1,只需定义_constructor:

import pandas as pd
import numpy as np

class MyDF(pd.DataFrame):
    @property
    def _constructor(self):
        return MyDF


mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)

mydf_sub = mydf[['A','C']]
print type(mydf_sub)
Run Code Online (Sandbox Code Playgroud)

我认为这是对要求2没有简单的解决办法,我想你需要定义__init__,copy或做一些事情_constructor,例如:

import pandas as pd
import numpy as np

class MyDF(pd.DataFrame):
    _attributes_ = "myattr1,myattr2"

    def __init__(self, *args, **kw):
        super(MyDF, self).__init__(*args, **kw)
        if len(args) == 1 and isinstance(args[0], MyDF):
            args[0]._copy_attrs(self)

    def _copy_attrs(self, df):
        for attr in self._attributes_.split(","):
            df.__dict__[attr] = getattr(self, attr, None)

    @property
    def _constructor(self):
        def f(*args, **kw):
            df = MyDF(*args, **kw)
            self._copy_attrs(df)
            return df
        return f

mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)

mydf_sub = mydf[['A','C']]
print type(mydf_sub)

mydf.myattr1 = 1
mydf_cp1 = MyDF(mydf)
mydf_cp2 = mydf.copy()
print mydf_cp1.myattr1, mydf_cp2.myattr1
Run Code Online (Sandbox Code Playgroud)