Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在不中断DataFrame.append()的情况下对DataFrame进行子类化或扩展?_Python_Python 3.x_Pandas - Fatal编程技术网

Python 如何在不中断DataFrame.append()的情况下对DataFrame进行子类化或扩展?

Python 如何在不中断DataFrame.append()的情况下对DataFrame进行子类化或扩展?,python,python-3.x,pandas,Python,Python 3.x,Pandas,我有一个复杂的对象,我想围绕熊猫数据帧构建。我曾尝试用一个子类来实现这一点,但在数据框中添加会重新初始化新实例中的所有属性,即使在使用\u metadata时也是如此。我知道不建议对pandas对象进行子类化,但我不知道如何使用composition(或任何其他方法)实现我想要的功能,因此如果有人能告诉我如何在不进行子类化的情况下实现这一点,那将是非常棒的 我正在使用以下代码: import pandas as pd class thisDF(pd.DataFrame): @prop

我有一个复杂的对象,我想围绕熊猫数据帧构建。我曾尝试用一个子类来实现这一点,但在数据框中添加会重新初始化新实例中的所有属性,即使在使用
\u metadata
时也是如此。我知道不建议对pandas对象进行子类化,但我不知道如何使用composition(或任何其他方法)实现我想要的功能,因此如果有人能告诉我如何在不进行子类化的情况下实现这一点,那将是非常棒的

我正在使用以下代码:

import pandas as pd

class thisDF(pd.DataFrame):

    @property
    def _constructor(self):
        return thisDF

    _metadata = ['new_property']

    def __init__(self, data=None, index=None, columns=None, copy=False, new_property='reset'):
        
        super(thisDF, self).__init__(data=data, index=index, columns=columns, dtype='str', copy=copy)

        self.new_property = new_property

cols = ['A', 'B', 'C']
new_property = cols[:2]
tdf = thisDF(columns=cols, new_property=new_property)
正如我在上面链接的示例中所示,像
tdf[['A','B']]这样的操作。新的_属性
可以很好地工作。但是,以创建新副本的方式修改数据会初始化不保留
new\u属性的新实例。那么代码呢

print(tdf.new_property)
tdf = tdf.append(pd.Series(['a', 'b', 'c'], index=tdf.columns), ignore_index=True)
print(tdf.new_property)
输出

['A', 'B']
reset
如何扩展
pd.DataFrame
,以便
thisDF.append()
保留实例属性(如果不使用子类,则保留一些等效的数据结构)?请注意,我可以通过创建一个以DataFrame作为属性的类来完成我想要的一切,但我不想对所有DataFrame操作执行
my_object.DataFrame.some_method()

“[…]或使用我的_object class方法包装所有DataFrame方法(因为我假设这将是一项大量工作,对吗?)

不,不需要做很多工作。实际上,您不必自己包装包装对象的每个函数。可以使用getattr将调用向下传递到包装对象,如下所示:

class WrappedDataFrame:
    def __init__(self, df, new_property):
        self._df = df
        self.new_property = new_property
    
    def __getattr__(self, attr):
        if attr in self.__dict__:
            return getattr(self, attr)
        return getattr(self._df, attr)
    
    def __getitem__(self, item):
        return self._df[item]
    
    def __setitem__(self, item, data):
        self._df[item] = data
\uuuu getattr\uuuu
是一个dunder方法,每次调用该类实例的方法时都会调用该方法。在我的实现中,每次隐式调用
\uuu getattr\uuu
时,它都会检查对象是否具有您正在调用的方法。如果是,则返回并执行该方法。否则,它将在包装对象的
\uuu dict\uu
中查找该方法并返回该方法

所以这个类在很大程度上就像一个数据帧一样工作。现在,您可以实现您想要的不同行为方式,如示例中的append

您可以使append修改包装的数据帧对象

    def append(self, *args, **kwargs):
        self._df = self._df.append(*args, **kwargs)
或者,它返回
WrappedDataFrame
类的一个新实例,当然它保留了您的所有功能

    def append(self, *args, **kwargs):
        return self.__class__(self._df.append(*args, **kwargs))

您希望您的复杂对象做什么,从而导致您对DataFrame进行子类化?我经常创建一个类,该类将dataframe作为属性,该类中的函数可能会操作dataframe。例如,
my\u object.add\u stuff(x)
可能调用
self.dataframe.append(x)
。该对象表示引用网络,其中包含书目的数据框、引用的源和目标的数据框,以及用于网络分析的NetworkX图。引用和图表是属性,但我想通过执行
my_object.DataFrameMethod()
来操作参考书目,而不是执行
my_object.bib.DataFrameMethod()
或使用
my_object
类方法包装所有数据框方法(因为我假设这将是大量工作,对吗?).这看起来对我有用,谢谢!我尝试过这样做,但我没有正确处理get/set项。