2016-04-22 14 views
3

Ich bin versucht, einen Wrapper für die statsmodels Formel API zu schreiben (dies ist eine vereinfachte Version, die Funktion ist mehr als diese):Fragen Namespace beim Aufruf von Patsy innerhalb einer Funktion

import statsmodels.formula.api as smf 

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

Wenn ich diese Funktion geben an einen Benutzer, der dann seine/ihre eigene Funktion zu definieren versucht:

def square(x): 
    return x**2 

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

werden sie ein NameError weil das patsy Modul sucht im Namensraum von wrapper für die Funktion square erhalten. Gibt es einen sicheren, pythonischen Weg, um mit dieser Situation umzugehen, ohne a priori zu wissen, was die Funktionsnamen sind oder wie viele Funktionen benötigt werden?

FYI: Dies ist für Python 3.4.3.

+0

Ich kenne nicht die Details (zu viel Magie für meinen Geschmack), aber die 'statsmodels.base.model.Model.from_formula' Docstring beschreibt eine' eval_env' kwd in ** kwarg, die Sie inkrementell erhöhen können by 1. 'from_formula' wird von allen oder den meisten Modellen vererbt. – user333700

+0

Ja, ich habe es versucht; schien nicht zu funktionieren, aber vielleicht habe ich es nicht richtig genannt. – chriswhite

+0

Haben Sie versucht, es auf 3 zu setzen? In einem ähnlichen Fall habe ich try..except wraping verwendet, um herauszufinden, in welcher Tiefe Benutzerfunktionen sind. – user333700

Antwort

2

statsmodels verwendet das patsy-Paket, um die Formeln zu analysieren und die Entwurfsmatrix zu erstellen. patsy erlaubt Benutzerfunktionen als Teil von Formeln und erhält oder wertet die Benutzerfunktion im Benutzernamensraum oder in der Umgebung aus.

als Referenz siehe eval_env Schlüsselwort in http://patsy.readthedocs.org/en/latest/API-reference.html

from_formula wird die Methode von Modellen, die die Formel Schnittstelle zu patsy implementiert. Es verwendet eval_env, um die notwendigen Informationen für Patsy bereitzustellen, die standardmäßig die aufrufende Umgebung des Benutzers ist. Dies kann vom Benutzer mit dem entsprechenden Schlüsselwortargument überschrieben werden.

Die einfachste Möglichkeit, eval_env zu definieren, ist eine Ganzzahl, die den Stacklevel angibt, den patsy verwenden soll. from_formula erhöht es, um die zusätzliche Ebene in den statsmodels-Methoden zu berücksichtigen.

Gemäß den Kommentaren wird eval_env = 2 die nächst höhere Ebene von der Ebene verwenden, die das Modell erstellt, z. mit model = smf.logit(..., eval_env=2).

Dies erstellt das Modell, ruft Patsy auf und erstellt die Entwurfsmatrix, model.fit() schätzt es und gibt die Ergebnisinstanz zurück.

+0

Wenn mehrere verschachtelte Wrapper vorhanden sind, wäre es sinnvoll, dies als Argument zu betrachten und nach dem Inkrementieren weiterzugeben. wie 'def f (..., eval_env = 1): ... smf.logit (..., eval_env = eval_env + 1)' –

+0

Wenn ich deinen Kommentar richtig verstehe, dann ist das was from_formula tut, https: //github.com/statsmodels/statsmodels/blob/master/statsmodels/base/model.py#L138 zB erhöhen, wenn vorhanden und hand on. Insgesamt würde ich Sicherheitsfragen überprüfen, bevor ich mich auf 'eval'-Ansätze ausdehne. – user333700

1

wenn Sie bereit sind eval zu verwenden, um das Heben schwerer Lasten Ihrer Funktion zu tun Sie einen Namespace aus den Argumenten wrapper und die lokalen Variablen auf den äußeren Rahmen konstruieren kann:

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) 

Ich weiß nicht wirklich Sehen Sie dies als einen Betrüger, da es scheint, was logit sowieso tut, damit es einen NameError auslöst, und solange wrapper_code nicht geändert wird und es keine Namenskonflikte gibt (wie das Verwenden von etwas genannt data) sollte dies tun, was Sie wollen.

+0

Oh, das ist super interessant und etwas, worüber ich nachdenken kann, wenn das komplizierter wird. Vielen Dank! – chriswhite

+0

Ein Problem, das ich nicht weiß, wie es in Fällen wie diesem funktioniert, ist, wenn wir (Modell oder Ergebnisse) die gleiche Information wieder benötigen, z. zum Bewerten oder Transformieren der erklärenden Variablen in "vorhersagen". PATSY hält die Informationen in der Nähe und benutzt einige "Eve" -Magie, AFAIK. – user333700

Verwandte Themen