在函数中调用 patsy 时的命名空间问题
Namespace issues when calling patsy within a function
我正在尝试为 statsmodels 公式编写一个包装器 API(这是一个简化版本,该函数的作用不止于此):
import statsmodels.formula.api as smf
def wrapper(formula, data, **kwargs):
return smf.logit(formula, data).fit(**kwargs)
如果我将此函数提供给用户,然后用户尝试定义 his/her 自己的函数:
def square(x):
return x**2
model = wrapper('y ~ x + square(x)', data=df)
他们将收到 NameError
,因为 patsy
模块正在 wrapper
的命名空间中查找函数 square
。在事先不知道函数名称是什么或需要多少函数的情况下,是否有一种安全的 Pythonic 方法来处理这种情况?
仅供参考:这是针对 Python 3.4.3.
如果您愿意使用 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
的东西)这应该做你想做的。
statsmodels 使用 patsy 包解析公式并创建设计矩阵。 patsy 允许用户函数作为公式的一部分,并在用户命名空间或环境中获取或评估用户函数。
作为参考参见 http://patsy.readthedocs.org/en/latest/API-reference.html
中的 eval_env 关键字
from_formula
是models的方法,实现patsy的公式接口。它使用 eval_env
向 patsy 提供必要的信息,默认情况下是用户的调用环境。这可以由用户使用相应的关键字参数覆盖。
定义 eval_env 的最简单方法是作为一个整数来指示 patsy 应该使用的堆栈级别。 from_formula 正在增加它以考虑 statsmodels 方法中的附加级别。
根据评论,eval_env = 2 将使用创建模型级别的下一个更高级别,例如model = smf.logit(..., eval_env=2)
.
这将创建模型、调用 patsy 并创建设计矩阵,model.fit()
将对其进行估计并 returns 结果实例。
我正在尝试为 statsmodels 公式编写一个包装器 API(这是一个简化版本,该函数的作用不止于此):
import statsmodels.formula.api as smf
def wrapper(formula, data, **kwargs):
return smf.logit(formula, data).fit(**kwargs)
如果我将此函数提供给用户,然后用户尝试定义 his/her 自己的函数:
def square(x):
return x**2
model = wrapper('y ~ x + square(x)', data=df)
他们将收到 NameError
,因为 patsy
模块正在 wrapper
的命名空间中查找函数 square
。在事先不知道函数名称是什么或需要多少函数的情况下,是否有一种安全的 Pythonic 方法来处理这种情况?
仅供参考:这是针对 Python 3.4.3.
如果您愿意使用 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
的东西)这应该做你想做的。
statsmodels 使用 patsy 包解析公式并创建设计矩阵。 patsy 允许用户函数作为公式的一部分,并在用户命名空间或环境中获取或评估用户函数。
作为参考参见 http://patsy.readthedocs.org/en/latest/API-reference.html
中的 eval_env 关键字from_formula
是models的方法,实现patsy的公式接口。它使用 eval_env
向 patsy 提供必要的信息,默认情况下是用户的调用环境。这可以由用户使用相应的关键字参数覆盖。
定义 eval_env 的最简单方法是作为一个整数来指示 patsy 应该使用的堆栈级别。 from_formula 正在增加它以考虑 statsmodels 方法中的附加级别。
根据评论,eval_env = 2 将使用创建模型级别的下一个更高级别,例如model = smf.logit(..., eval_env=2)
.
这将创建模型、调用 patsy 并创建设计矩阵,model.fit()
将对其进行估计并 returns 结果实例。