2014-04-13 2 views
2

나는 모두 동일한 팬더 데이터 프레임을 참조하지만, 데이터 프레임의 일부만 각 클래스와 관련이있는 여러 클래스가 있습니다. 색인의 수준에 따라 번호가 중복되어 고급 색인 생성을 사용하지 않고 관련 행에 쉽게 액세스하려고합니다. 결과적으로 각 클래스가 슬라이스를 볼 수 있도록 부분 함수를 생성하는 코드를 작성했습니다. 참조가 foo.x처럼() [날짜]를 볼 필요가 없습니다 않았다 대신 foo.x [날짜]과 같이 할 수 있다면팬더를 동적으로 생성하기

from functools import partial 
import pandas as pd 
import numpy as np 
import dateutil.relativedelta as rd 
import datetime as dt 

class baz(object): 
    pass 

groups = ['foo', 'foo', 'bar', 'bar'] 
items = ['x','y', 'x', 'y'] 
diff = rd.relativedelta(years=1) 

dates = [dt.date(2013,1,1) + (diff * shift) for shift in xrange(4)] * 2 
index = pd.MultiIndex.from_arrays([groups, items], names=['groups', 'items']) 
values = np.random.randn(4,8) 

data = pd.DataFrame(values, index=index, columns=dates) 

def view_data(group, item): 
    return data.ix[group, item] 

foo = baz() 
bar = baz() 

# I use partial because I want lazy evaluation 
foo.x = partial(view_data, 'foo', 'x') 
foo.y = partial(view_data, 'foo', 'y') 
bar.x = partial(view_data, 'bar', 'x') 
bar.y = partial(view_data, 'bar', 'y') 

foo.x() 

그러나, 나는 선호 할 것입니다.

결과적으로 함수를 래핑하고 값을 반환하는 데코레이터를 만들었습니다.

def execute_func(func): 
    def inner(*args, **kwargs): 
     return func(*args, **kwargs) 
    return inner() 

foo.x = execute_func(partial(view_data, 'foo', 'x')) 
foo.y = execute_func(partial(view_data, 'foo', 'y')) 
bar.x = execute_func(partial(view_data, 'bar', 'x')) 
bar.y = execute_func(partial(view_data, 'bar', 'y')) 

저는 항상 데이터 프레임의 현재 상태를 가져 오지 않을 것이라고 우려하고 있습니다.

내 목표를 달성하는 데 올바른 방법인가요?

답변

3

잘 나는 개인적으로 당신과 같이 객체에 DataFrame 포장 제안 :

class MyDataFrameView(object): 

    def __init__(self, df): 
     self.data = df 

    def x(self): 
     return self.data.ix['foo', 'x'] 

    def y(self): 
     return self.data.ix['bar', 'y'] 

을 그렇게처럼 사용

df = MyDataFrameView(data) 
df.x() 

당신은 더 나아가 속성처럼 방법을 추가 할 수 있습니다 그것은 직관적으로 더 의미가 있습니다.

@property 
def y(self): 
    return self.data.ix['bar', 'y'] 

지금처럼 그것은 본질적으로 같은 일을하고 있지만, 더 간단 객체 지향 프로그래밍의 - 적어도 내 의견으로는 - 더 많이 이해합니다.

당신은 항상처럼 dataframe에 액세스 할 수 있습니다

df.data 

또는 다음, 당신이보기 개체에 직접 더 팬더 방법을 구현할 수, 예를 들면 :

@property 
def ix(self): 
    return self.data.ix 

def __getitem__(self, key): 
    return self.data.__getitem__(key) 

그래서 당신이 더 많은 동작 객체 DataFrame처럼.

메모는 실제로 "동적 인"것이 아닙니다. 당신이 진정으로 동적 인 방법을 원하는 경우에, 당신은뿐만 아니라

def __getattr__(self, attr): 
    #code that "routes" to do the right thing given attr 

이 패턴은 일반적으로 구성이라고하고 "문제"

+0

대안을 구현하는 나의 마음에 드는 방법이라는 것을 구현하기 위해 getattr에게 방법을 사용할 수 있습니다 '@property def x() : ...;를 사용하여 모든 DataFrames에 속성으로서 x를 추가하는 것입니다. pd.DataFrame.x = x', DataFrame을 직접 서브 클래 싱하는 것도 옵션입니다 ... –

관련 문제