python / pandas: наследование DataFrame и обновление DataFrame, когда 'inplace' невозможно - PullRequest
1 голос
/ 21 июня 2020

Извините, я знаю, что заголовок несколько нечеткий.

Контекст

Я использую Dataframe для отслеживания файлов, потому что pandas DataFrame содержит несколько соответствующие функции для выполнения всех видов фильтрации, которые не могут выполнять dict, с loc, pd.IndexSlice, .index, .columns, pd.MultiIndex ... Хорошо, так что это может показаться не лучшим выбором для опытных разработчиков (чего я не являюсь), но все эти функции были настолько удобны, что я использовал для этого DataFrame. И вишенка на торте, __repr__ из MultiIndex Dataframe просто идеально подходит, когда я хочу знать, что находится внутри моего списка файлов.

Краткое введение в класс Summary, наследующий от DataFrame

Поскольку мой DataFrame, который я называю «Сводка», имеет некоторые специфические c функции, я хотел бы сделать его классом, унаследованным от pandas DataFrame класса. Он также имеет «фиксированные» MultiIndexes для строк и столбцов.

Наконец, поскольку мой класс Summary определен вне класса Store, который фактически управляет файловой организацией, классу Summary нужна функция из Store, чтобы иметь возможность получить организацию файлов.

Вопросы

Проблема с pd.DataFrame (AFAIK): вы не можете добавлять строки без создания нового DataFrame. Поскольку Summary имеет функцию refresh, так что он может recreate сам читать содержимое папки, refresh каким-то образом «сбрасывает» объект «Сводка». Чтобы управлять Summary refre sh, я придумал первый код (не работает) и, наконец, второй (рабочий).

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

Этот код работает!

У меня 2 вопроса:

  • почему 1-й код не работает? (Извините, это может быть очевидно, но я совершенно не понимаю, почему это не работает)

  • вызывает super().__init__ в моем методе refresh приемлемая практика кодирования? (или перефразируя иначе: допустимо ли набирать super().__init__ в других местах, кроме __init__ моего подкласса?)

Большое спасибо за вашу помощь и совет. Мир наследования классов для меня совершенно новый, и тот факт, что содержимое DataFrame не может быть изменено напрямую, так сказать, мне кажется, делает его более сложным для обработки.

Хорошего day, Bests,

Сообщение об ошибке при добавлении новой строки

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]"

1 Ответ

1 голос
/ 21 июня 2020

Ответы на ваши вопросы

почему не работает 1-й код?

Вы пытаетесь вызвать класс, от которого унаследовали. Честно говоря, я не знаю, что именно происходит в вашем случае. Я предполагал, что это приведет к ошибке, но у вас пустой фрейм данных.

вызывает super().__init__ в моем методе refre sh приемлемая практика кодирования?

Может быть, Существует законный вариант использования для вызова super().__init__ вне метода __init __ (). Но ваш случай к их числу не относится. Вы уже унаследовали все от вашего __init __ (). Зачем снова его использовать?

Лучшее решение

Решение вашей проблемы неожиданно простое. Потому что вы можете добавить строку в Dataframe :

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

Или в вашем случае с MultiIndex (см. this SO пост ):

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

Лучшая практика

Вы не должны наследовать от pd.DataFrame. Если вы хотите расширить pandas, используйте задокументированный API .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...