Подтвердить что ты не робот

Как подкласс pandas DataFrame?

Подклассы pandas классы кажутся общей потребностью, но я не мог найти ссылки на эту тему. (Похоже, что разработчики pandas все еще работают над этим: https://github.com/pydata/pandas/issues/60).

Есть некоторые SO-потоки по этому вопросу, но я надеюсь, что кто-то здесь может предоставить более систематическую учетную запись в настоящее время лучшим способом подкласса pandas.DataFrame, который удовлетворяет двум, я думаю, общим требованиям:

import numpy as np
import pandas as pd

class MyDF(pd.DataFrame):
    # how to subclass pandas DataFrame?
    pass

mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)  # <class '__main__.MyDF'>

# Requirement 1: Instances of MyDF, when calling standard methods of DataFrame,
# should produce instances of MyDF.
mydf_sub = mydf[['A','C']]
print type(mydf_sub)  # <class 'pandas.core.frame.DataFrame'>

# Requirement 2: Attributes attached to instances of MyDF, when calling standard 
# methods of DataFrame, should still attach to the output.
mydf.myattr = 1
mydf_cp1 = MyDF(mydf)
mydf_cp2 = mydf.copy()
print hasattr(mydf_cp1, 'myattr')  # False
print hasattr(mydf_cp2, 'myattr')  # False

И существуют ли существенные различия для подкласса pandas.Series? Спасибо.

4b9b3361

Ответ 1

В настоящее время существует официальное руководство о том, как подклассы Pandas структуры данных, включая DataFrame, а также Series.

Руководство доступно здесь: http://pandas.pydata.org/pandas-docs/stable/internals.html#subclassing-pandas-data-structures

В руководстве в качестве примера можно привести этот подклассовый DataFrame из проекта Geopandas: https://github.com/geopandas/geopandas/blob/master/geopandas/geodataframe.py

Как и в ответе HYRY, кажется, есть две вещи, которые вы пытаетесь выполнить:

  • При вызове методов в экземпляре вашего класса возвращайте экземпляры нужного типа (ваш тип). Для этого вы можете просто добавить свойство _constructor, которое должно вернуть ваш тип.
  • Добавление атрибутов, которые будут прикреплены к копиям вашего объекта. Для этого вам нужно сохранить имена этих атрибутов в списке, как специальный атрибут _metadata.

Вот пример:

class SubclassedDataFrame(DataFrame):
    _metadata = ['added_property']
    added_property = 1  # This will be passed to copies

    @property
    def _constructor(self):
        return SubclassedDataFrame

Ответ 2

Для требования 1 просто определите _constructor:

import pandas as pd
import numpy as np

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


mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)

mydf_sub = mydf[['A','C']]
print type(mydf_sub)

Я думаю, что нет простого решения для требования 2, я думаю, вам нужно определить __init__, copy или сделать что-то в _constructor, например:

import pandas as pd
import numpy as np

class MyDF(pd.DataFrame):
    _attributes_ = "myattr1,myattr2"

    def __init__(self, *args, **kw):
        super(MyDF, self).__init__(*args, **kw)
        if len(args) == 1 and isinstance(args[0], MyDF):
            args[0]._copy_attrs(self)

    def _copy_attrs(self, df):
        for attr in self._attributes_.split(","):
            df.__dict__[attr] = getattr(self, attr, None)

    @property
    def _constructor(self):
        def f(*args, **kw):
            df = MyDF(*args, **kw)
            self._copy_attrs(df)
            return df
        return f

mydf = MyDF(np.random.randn(3,4), columns=['A','B','C','D'])
print type(mydf)

mydf_sub = mydf[['A','C']]
print type(mydf_sub)

mydf.myattr1 = 1
mydf_cp1 = MyDF(mydf)
mydf_cp2 = mydf.copy()
print mydf_cp1.myattr1, mydf_cp2.myattr1