使用所需参数对pandas DataFrame进行子类化

7
我正在开发一个继承pandas DataFrame的新数据结构。我想要强制我的新数据结构具有new_property,以便稍后可以安全地处理它。 然而,当使用我的新数据结构时,我遇到了错误,因为一些内部的pandas函数调用了构造函数,但没有所需的属性。 以下是我的新数据结构。
import pandas as pd
class MyDataFrame(pd.DataFrame):

    @property
    def _constructor(self):
        return MyDataFrame

    _metadata = ['new_property']

    def __init__(self, data, new_property, index=None, columns=None, dtype=None, copy=True):

        super(MyDataFrame, self).__init__(data=data,
                                          index=index,
                                          columns=columns,
                                          dtype=dtype,
                                          copy=copy)
        self.new_property = new_property

这是一个导致错误的示例

data1 = {'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [15, 25, 30], 'd': [1, 1, 2]}
df1 = MyDataFrame(data1, new_property='value')
df1[['a', 'b']]

以下是错误信息

Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 2881, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-33-b630fbf14234>", line 1, in <module>
    df1[['a', 'b']]
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py", line 2053, in __getitem__
    return self._getitem_array(key)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\frame.py", line 2098, in _getitem_array
    return self.take(indexer, axis=1, convert=True)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\generic.py", line 1670, in take
    result = self._constructor(new_data).__finalize__(self)
TypeError: __init__() missing 1 required positional argument: 'new_property'

这个问题有没有解决方法或者其他的设计方式,可以强制我的新数据结构有新属性?

提前感谢!

2个回答

5

这个问题已经被一位出色的Pandas开发者回答了。请参见此问题以获取更多详细信息。将答案粘贴在此处。

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

    _metadata = ['new_property']

    @classmethod
    def _internal_ctor(cls, *args, **kwargs):
        kwargs['new_property'] = None
        return cls(*args, **kwargs)

    def __init__(self, data, new_property, index=None, columns=None, dtype=None, copy=True):
        super(MyDataFrame, self).__init__(data=data,
                                      index=index,
                                      columns=columns,
                                      dtype=dtype,
                                      copy=copy)
        self.new_property = new_property

data1 = {'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [15, 25, 30], 'd': [1, 1, 2]}
df1 = MyDataFrame(data1, new_property='value')

df1[['a', 'b']].new_property
Out[121]: 'value'

MyDataFrame(data1)
TypeError: __init__() missing 1 required positional argument: 'new_property'

Pandas文档中相关部分似乎是:http://pandas.pydata.org/pandas-docs/stable/internals.html#define-original-properties - MrDrFenner

0

我知道这是一个旧问题,但我想要扩展hlu的答案。

当实现hlu所描述的答案时,只尝试打印子类DataFrame时,我遇到了以下错误:AttributeError: 'internal_constructor' object has no attribute '_from_axes'

为了修复这个问题,我使用了一个对象而不是hlu答案中使用的函数,以便能够在可调用对象上实现_from_axes方法。

没有_classmethod_类型修饰符用于_internal_constructor类,因此我们使用调用程序类对其进行实例化,以便在调用_internal_constructor时可以使用它。

class MyDataFrame(pd.DataFrame):
    @property
    def _constructor(self):
        return MyDataFrame._internal_constructor(self.__class__)

    class _internal_constructor(object):
        def __init__(self, cls):
            self.cls = cls

        def __call__(self, *args, **kwargs):
            kwargs['my_required_argument'] = None
            return self.cls(*args, **kwargs)

        def _from_axes(self, *args, **kwargs):
            return self.cls._from_axes(*args, **kwargs)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接