python/pandas: 当 'inplace' 不可能时,DataFrame 继承和 DataFrame 更新

python/pandas: DataFrame inheritance and DataFrame update when 'inplace' is not possible

对不起,我知道标题有点模糊。

上下文

我正在使用 Dataframe 来跟踪文件,因为 pandas DataFrame 具有几个相关功能来执行字典无法执行的所有类型的过滤, loc, pd.IndexSlice, .index, .columns, pd.MultiIndex... 好吧,这可能不是专业开发人员的最佳选择(我不是),但所有这些功能都非常方便,我已经开始使用 DataFrame 来实现这一点。 蛋糕上的樱桃,MultiIndex Dataframe__repr__ 当我想知道我的文件列表中有什么时,它是完美的。

Summary class 的快速介绍,继承自 DataFrame

因为我的DataFrame,我叫'Summary',有一些特定的功能,我想把它做成class,继承自pandas DataFrame class。 它还具有 'fixed' MultiIndexes,用于行和列。

最后,因为我的Summaryclass是在Storeclass之外定义的,它实际上是管理文件组织,Summaryclass需要 Store 中的函数才能检索文件组织。

问题

pd.DataFrame 的问题是(据我所知)您不能在不创建新的 DataFrame 的情况下追加行。 由于 Summary 具有 refresh 功能,因此它可以通过读取文件夹内容来 recreate 自身, refresh 以某种方式 'reset' 'Summary' object. 为了管理 Summary 刷​​新,我想出了第一个代码(不工作),最后是第二个(工作)。

import pandas as pd
import numpy as np

# Dummy function
def summa(a,b):
    return a+b

# Does not work
class DatF1(pd.DataFrame):

    def __init__(self,meth,data=None):
        cmidx = pd.MultiIndex.from_arrays([['Index', 'Index'],['First', 'Last']])
        rmidx = pd.MultiIndex(levels=[[],[]], codes=[[],[]],
                              names=['Component','Interval'])
        super().__init__(data=data, index=rmidx, columns=cmidx, dtype=np.datetime64)
        self.meth=meth

    def refresh(self):
        values = [[pd.Timestamp('2020/02/10 8:00'),pd.Timestamp('2020/02/10 8:00')],
                  [pd.Timestamp('2020/02/11 8:00'),pd.Timestamp('2020/02/12 8:00')]]
        rmidx = pd.MultiIndex.from_arrays([['Comp1','Comp1'],['1h','1W']],names=['Component','Interval'])
        self = pd.DataFrame(values, index=rmidx, columns=self.columns)

ex1 = DatF1(summa)

In [10]: ex1.meth(3,4)
Out[10]: 7

ex1.refresh()
In [11]: ex1
Out[11]: Empty DatF1
         Columns: [(Index, First), (Index, Last)]
         Index: []

refresh()之后,ex1还是空的。 refresh 工作不正常。

# Works
class DatF2(pd.DataFrame):

    def __init__(self,meth,data=None):
        cmidx = pd.MultiIndex.from_arrays([['Index', 'Index'],['First', 'Last']])
        rmidx = pd.MultiIndex(levels=[[],[]], codes=[[],[]],
                              names=['Component','Interval'])
        super().__init__(data=data, index=rmidx, columns=cmidx, dtype=np.datetime64)
        self.meth=meth

    def refresh(self):
        values = [[pd.Timestamp('2020/02/10 8:00'),pd.Timestamp('2020/02/10 8:00')],
                  [pd.Timestamp('2020/02/11 8:00'),pd.Timestamp('2020/02/12 8:00')]]
        rmidx = pd.MultiIndex.from_arrays([['Comp1','Comp1'],['1h','1W']],names=['Component','Interval'])
        super().__init__(values, index=rmidx, columns=self.columns)

    ex2 = DatF2(summa)

    In [10]: ex2.meth(3,4)
    Out[10]: 7

    ex2.refresh()
    In [11]: ex2
    Out[11]:                                  Index                    
                                              First                Last
             Component Interval                                        
             Comp1     1h       2020-02-10 08:00:00 2020-02-10 08:00:00
                       1W       2020-02-11 08:00:00 2020-02-12 08:00:00

此代码有效!

我有两个问题:

非常感谢您的帮助和建议。 class 继承的世界对我来说很新鲜,而且 DataFrame 内容不能直接修改,这么说,在我看来似乎更难处理。

祝你有美好的一天, 最佳,

添加新行时出现错误消息

import pandas as pd
import numpy as np

# Dummy function
def new_rows():
    return [['Comp1','Comp1'],['1h','1W']]

# Does not work
class DatF1(pd.DataFrame):

    def __init__(self,meth,data=None):
        cmidx = pd.MultiIndex.from_arrays([['Index', 'Index'],['First', 'Last']])
        rmidx = pd.MultiIndex(levels=[[],[]], codes=[[],[]],
                          names=['Component','Interval'])
        super().__init__(data=data, index=rmidx, columns=cmidx, dtype=np.datetime64)
        self.meth=meth

    def refresh(self):
        values = [[pd.Timestamp('2020/02/10 8:00'),pd.Timestamp('2020/02/10 8:00')],
                  [pd.Timestamp('2020/02/11 8:00'),pd.Timestamp('2020/02/12 8:00')]]
        rmidx = self.meth()
        self[rmidx] = values

ex1 = DatF1(new_rows)
ex1.refresh()

KeyError: "None of [MultiIndex([('Comp1', 'Comp1'),\n            (   '1h',    '1W')],\n           names=['Component', 'Interval'])] are in the [index]"

您问题的答案

why the 1st code is not working?

您正在尝试调用您继承自的 class。老实说,我不知道你的情况到底发生了什么。我以为这会产生错误,但你得到的是一个空数据框。

is calling super().__init__ in my refresh method acceptable coding practise?

可能存在在 __init__() 方法之外调用 super().__init__ 的合法用例。但你的情况不是其中之一。您已经从 __init__() 中继承了一切。为什么要再次使用它?


更好的解决方案

解决你的问题出乎意料的简单。因为你可以 append a row to a Dataframe:

df['new_row'] = [value_1, value_2, ...]

或者在您使用 MultiIndex 的情况下(参见 this SO post):

  df.loc[('1h', '1W'), :] = [pd.Timestamp('2020/02/10 8:00'), pd.Timestamp('2020/02/10 8:00')]

最佳实践

您不应该继承自 pd.DataFrame。如果你想扩展 pandas 使用 documented API.