我有几个类都引用相同的pandas数据帧,但只有部分数据框与每个类相关。我还希望在不使用高级索引的情况下轻松访问相关行,因为索引中的数字级别会导致重复。因此,我编写了生成部分函数的代码,以便每个类都可以查看其切片。
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()
但是,如果引用不必看起来像foo.x()[date],我宁愿看起来像foo.x [date]。
结果,我创建了一个装饰器,它将包装函数并返回值。
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'))
我担心的是,我不会总是得到数据帧的当前状态。
这是实现目标的正确方法吗?
答案 0 :(得分: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']
它基本上就像你现在做的一样,但它更直接的面向对象编程 - 至少在我看来 - 更好理解。
您可以随时访问您的数据框:
df.data
或者,您可以直接在View对象上实现更多pandas方法,例如:
@property
def ix(self):
return self.data.ix
def __getitem__(self, key):
return self.data.__getitem__(key)
所以你的对象行为更像是一个DataFrame。
请注意,这不是真正的“动态”。如果你想要一个真正动态的方式,你可以使用 getattr 方法来实现它
def __getattr__(self, attr):
#code that "routes" to do the right thing given attr
这种模式通常被称为组合,是我最喜欢的实现“问题”的方式