首页 > 解决方案 > `pandas` `DataFrame` 类的包装器

问题描述

使用这个pandas包,我经常对DataFrame实例进行类似的计算。为了使事情更容易,我创建了一个类 ( ),它是我经常使用PfFrame的附加属性的包装器。pandas.DataFrame这有效:

import pandas as pd

class PfFrame(pd.DataFrame):
    """PortfolioFrame; thin wrapper around pandas DataFrame."""
    # (here are the custom attributes of this class)
    pass

但是,所有返回实例的继承方法pandas.DataFrame都应改为返回实例PfFrame我在下面的代码中实现了这个模式,但是我得到了一个错误——我在想,由于基类的复杂性更高。

import pandas as pd
import numpy as np

def pf_i(val):
    """Turn DataFrame instance into PfFrame instance."""
    if type(val) is pd.DataFrame:
        val = PfFrame(val)
    return val

def pf_f(func):
    """Turn from DataFrame- to PfFrame-instance-returning function."""
    def wrapper(*args, **kwargs):
        val = func(*args, **kwargs)
        return pf_i(val)        
    return wrapper

class PfMeta(type):
    def __new__(cls, name, bases, dct):
        klass = super().__new__(cls, name, bases, dct)
        for base in bases:
            for field_name, field in base.__dict__.items():
                if callable(field):
                    setattr(klass, field_name, pf_f(field))
        return klass

class PfFrame(pd.DataFrame, metaclass=PfMeta):
    """PortfolioFrame; thin wrapper around pandas DataFrame."""
    # (here are the custom attributes of this class)
    pass

(我已将代码减少到最低限度,并省略了特定属性,因为我的问题在此之前出现。)

有什么想法可以让它发挥作用吗?

多谢!

附加信息

1

创建基类和子类的实例时,不会引发错误:

df = pd.DataFrame(np.arange(6).reshape(3, 2), columns=list('ab'))
pfframe = PfFrame(np.arange(6).reshape(3, 2), columns=list('ab'))

但是,做任何事情都会pfframe引发错误:

pfframe.a  # should return a pandas.Series
TypeError: __init__() got multiple values for argument 'index'
pfframe[['a', 'b']]  # should return a PfFrame
TypeError: __init__() got multiple values for argument 'index'
dir(pfframe)  # should return a simple dict
TypeError: __init__() got multiple values for argument 'index'

2

尽管如此,将它传递给pandas.DataFrame构造函数仍然可以正常工作:

pd.DataFrame(pfframe)
    a   b
0   0   1
1   2   3
2   4   5

3

我认为该__init__方法的包装可能是由问题引起的。但是,将if callable(field):行更改为添加if callable(field) and field_name != "__init__":没有任何区别。

4

替代解决方案:我目前只有几个属性,可以直接附加它们pd.DataFrame,一步解决我的问题。但是,我觉得这很污染,让用户的事情变得更难。

标签: pythonpython-3.xpandasdataframe

解决方案


推荐阅读