在函数中调用patsy时发生命名空间问题

时间:2016-04-22 16:29:14

标签: python python-3.x namespaces statsmodels patsy

我正在尝试为statsmodels公式API编写一个包装器(这是一个简化版本,该函数不仅仅是这个):

import statsmodels.formula.api as smf

def wrapper(formula, data, **kwargs):
    return smf.logit(formula, data).fit(**kwargs)

如果我将此功能提供给用户,然后用户尝试定义他/她自己的功能:

def square(x):
    return x**2

model = wrapper('y ~ x + square(x)', data=df)

他们将收到NameError因为patsy模块在​​wrapper的名称空间中查找函数square。是否有一种安全的Pythonic方法来处理这种情况,而不知道函数名称是什么或需要多少函数?

仅供参考:这是Python 3.4.3。

2 个答案:

答案 0 :(得分:2)

statsmodels使用patsy包来解析公式并创建设计矩阵。 patsy允许用户函数作为公式的一部分,并在用户命名空间或环境中获取或评估用户函数。

作为参考,请参阅http://patsy.readthedocs.org/en/latest/API-reference.html

中的eval_env关键字

from_formula是实现patsy的公式接口的模型方法。它使用eval_env为patsy提供必要的信息,默认情况下是用户的调用环境。用户可以使用相应的关键字参数覆盖它。

定义eval_env的最简单方法是一个整数,表示patsy应该使用的stacklevel。 from_formula正在递增它以考虑statsmodels方法中的附加级别。

根据评论,eval_env = 2将使用创建模型的级别中的下一个更高级别,例如与model = smf.logit(..., eval_env=2)

这会创建模型,调用patsy并创建设计矩阵,model.fit()将估计它并返回结果实例。

答案 1 :(得分:1)

如果你愿意使用eval来完成你的函数繁重的工作,你可以从wrapper的参数和局部变量到外框构造一个命名空间:

wrapper_code = compile("smf.logit(formula, data).fit(**kwargs)",
                       "<WrapperFunction>","eval")
def wrapper(formula,data,**kwargs):
    outer_frame = sys._getframe(1)
    namespace = dict(outer_frame.f_locals)
    namespace.update(formula=formula, data=data, kwargs=kwargs, smf=smf)
    return eval(wrapper_code,namespace)

我真的不认为这是作弊,因为它似乎是logit正在做的事情,因为它引发了一个NameError,并且只要wrapper_code没有被修改而且没有名称冲突(比如使用名为data的东西)这应该做你想要的。