我正在尝试为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。
答案 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
的东西)这应该做你想要的。