2014-11-01 3 views
0

Я пытаюсь расширить панд DataFrame следующим кодомМетод цепочки для производного DataFrame класса

class CustomFrame(DataFrame): 
    def __init__(self): 
     DataFrame.__init__(self,{"a":[1,2,3,4],"b":[5,6,7,8]}) 
    def get(self): 
     return self.loc[1] 
    def foo(self): 
     return 2*self 

Теперь я хотел цепной метод вызовов, как:

>>> c=CustomFrame() 
>>> c.get().foo() 
'Series' object has no attribute 'foo' 

очевидно .loc возвращает серию, которая ничего не знает о обычном методе foo. Есть ли способ сделать эту работу?

Edit:

В идеале я хотел бы сделать что-то вроде

c.method_from_data_frame().method_from_custom_frame().another_method_from_data_frame() 

Следуя совету HYRY я переопределен конструктор DataFrame, однако мне нужно установить некоторые свойства инициализации от CustomFrame

class CustomFrame(DataFrame): 
    def __init__(self, *args, **kw): 
     super(CustomFrame, self).__init__(*args, **kw) 
     self.c = kw.get('c',False) 

    @property 
    def _constructor(self): 
     return CustomFrame 

    >>> c=CustomFrame(c=5) 
    >>> print c.c 
    5 
    >>> print c.get().c 
    False 

Я попытался использовать functoolspartial

@property 
    def _constructor(self): 
     return partial(CustomFrame,c=5) 

, но я получаю ошибку pandas.core.common.PandasError: DataFrame constructor not properly called!. Другой способ изменить get к

def get(self): 
     ret = self.loc[[1]] # CustomFrame with default .c 
     ret.c = self.c 
     return ret 

, который, кажется, не очень элегантный

+3

Либо переопределить 'loc' вернуть' CustomFrame', или преобразовать возвращаемое значение в ' get'. – jonrsharpe

+0

@jonrsharpe mmmh overriding 'DataFrame.loc' подразумевает переопределение каждого метода, возвращающего значение, которое я, возможно, хочу связать. – greole

+0

Ну ... да, иначе вы не получите 'CustomFrame'. Я полагаю, вы могли бы что-то сделать с '__getattribute__'. – jonrsharpe

ответ

1

Вы можете переопределить _constructor свойство, вот пример, потому что self.loc[1] возвращает объект серии, я изменил его на self.loc[[1]]:

from pandas import DataFrame 


class CustomFrame(DataFrame): 
    def __init__(self, *args, **kw): 
     super(CustomFrame, self).__init__(*args, **kw) 

    @property 
    def _constructor(self): 
     return CustomFrame   

    def get(self): 
     return self.loc[[1]] 

    def foo(self): 
     return 2*self 

c=CustomFrame({"a":[1,2,3,4],"b":[5,6,7,8]}) 
print c.get().foo() 

Редактировать

Я не лучшая идея, чтобы скопировать атрибуты, может быть, вы можете использовать _metadata или декоратор, вот пример с декоратора:

def copy_attrs(func): 
    def wrap_func(self, *args, **kw): 
     res = func(self, *args, **kw) 
     res.c = self.c 
     return res 
    return wrap_func 

class CustomFrame(DataFrame): 
    def __init__(self, *args, **kw): 
     self.__dict__["c"] = kw.pop("c", None)  
     super(CustomFrame, self).__init__(*args, **kw) 

    @property 
    def _constructor(self): 
     return CustomFrame 

    @copy_attrs 
    def get(self): 
     return self.loc[:2] 

df = CustomFrame({"a":[1,2,3,4],"b":[5,6,7,8]}, c=100) 
print df.c, df.get().c 
+0

Интересно, может ли это как-то быть расширено, чтобы я мог передавать/инициализировать свойства созданного 'CustomFrame'? – greole

+0

@ greole, можете ли вы добавить пример? – HYRY

+0

Я обновил свой вопрос – greole

Смежные вопросы