【问题标题】:Dynamically Generating Pandas Views动态生成 Pandas 视图
【发布时间】:2014-04-13 14:26:54
【问题描述】:

我有几个类都引用同一个 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'))

我担心我不会总是获得数据框的当前状态。

这是实现我的目标的正确方法吗?

【问题讨论】:

    标签: python pandas functools


    【解决方案1】:

    我个人建议您将 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
    

    这种模式通常称为组合,也是我最喜欢的实现“问题”的方式

    【讨论】:

    • 另一种方法是将x作为属性添加到所有带有@property def x(): ...; pd.DataFrame.x = x的DataFrame,直接子类化DataFrame也是一种选择...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-30
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多