繁体   English   中英

相当于Python中的Stata宏

[英]Equivalent of Stata macros in Python

我正在尝试使用Python进行统计分析。

在Stata中,我可以定义本地宏并根据需要展开它们:

program define reg2
    syntax varlist(min=1 max=1), indepvars(string) results(string)
    if "`results'" == "y" {
        reg `varlist' `indepvars'
    }
    if "`results'" == "n" {
        qui reg `varlist' `indepvars'
    }
end

sysuse auto, clear

所以代替:

reg2 mpg, indepvars("weight foreign price") results("y")

我可以做:

local options , indepvars(weight foreign price) results(y) 
reg2 mpg `options'

甚至:

local vars weight foreign price
local options , indepvars(`vars') results(y) 
reg2 mpg `options'

Stata中的宏帮助我编写干净的脚本,而无需重复代码。

在Python中我尝试了字符串插值,但这在函数中不起作用。

例如:

def reg2(depvar, indepvars, results):
    print(depvar)
    print(indepvars)
    print(results)

以下运行正常:

reg2('mpg', 'weight foreign price', 'y')

但是,这两个都失败了:

regargs = 'mpg', 'weight foreign price', 'y'
reg2(regargs)

regargs = 'depvar=mpg, covariates=weight foreign price, results=y'
reg2(regargs)

我发现了一个类似的问题,但它没有回答我的问题:

R还有另一个问题:

但是,我找不到Python的任何内容。

我想知道Python中是否有类似于Stata宏的东西?

这是Pythonic的方式。

在Stata中普遍使用宏反映了不同的编程哲学。 与Python(一种面向对象的通用编程语言)不同,Stata的ado语言(不是mata )需要宏才能使其不仅仅是一种简单的脚本语言。

出于两个目的,宏几乎可以在Stata中的任何地方使用(即使在宏定义中):

  1. 文字替换
  2. 表达评估

使用宏,用户可以简化他们的代码,从而减少错误的可能性并保持整洁。 缺点是宏的使用呈现语言流的语法。

为了回答你的问题, Pyexpander在Python中提供了一些这样的功能,但它并不是真正的替代品。 对于不同的用例,您需要一种不同的方法来模拟宏扩展。 与Stata相比,在任何地方都没有统一的方法。

我的建议是熟悉Python的惯例,而不是试图用“Stata方式”来编程 例如,要记住,在Stata本地和全局宏对应Python中的变量(本地的功能,全球外),而在Stata变量对应于有用Pandas.Series或一列Pandas.DataFrame 同样,Stata ado程序对应于Python中的函数。

@ gddc答案中提供的解决方案可以成为实现某人想要的好工具。 但是,如果要重新使用代码,则需要执行额外的步骤。

使用你的玩具示例:

import pandas as pd   
import numpy as np      
import statsmodels.api as sm

df = pd.read_stata('http://www.stata-press.com/data/r14/auto.dta')

In [1]: df[['mpg', 'weight', 'price']].head()
Out[1]: 
   mpg  weight  price
0   22    2930   4099
1   17    3350   4749
2   22    2640   3799
3   20    3250   4816
4   15    4080   7827

假设您想要重复使用以下代码片段,但使用不同的变量:

In [2]: Y = df['mpg']
In [3]: df['cons'] = 1
In [4]: X = df[['weight', 'price', 'cons']]

In [5]: reg = sm.OLS(Y, X).fit()
In [6]: print(reg.summary())
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    mpg   R-squared:                       0.653
Model:                            OLS   Adj. R-squared:                  0.643
Method:                 Least Squares   F-statistic:                     66.85
Date:                                   Prob (F-statistic):           4.73e-17
Time:                                   Log-Likelihood:                -195.22
No. Observations:                  74   AIC:                             396.4
Df Residuals:                      71   BIC:                             403.3
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
weight        -0.0058      0.001     -9.421      0.000      -0.007      -0.005
price      -9.351e-05      0.000     -0.575      0.567      -0.000       0.000
cons          19.7198      0.811     24.322      0.000      18.103      21.336
==============================================================================
Omnibus:                       29.900   Durbin-Watson:                   2.347
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               60.190
Skew:                           1.422   Prob(JB):                     8.51e-14
Kurtosis:                       6.382   Cond. No.                     1.50e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.5e+04. This might indicate that there are
strong multicollinearity or other numerical problems.

你怎么可能那样做?

首先,创建一个函数

def reg2(depvar, indepvars, results, df):
    Y = df[depvar]
    df['cons'] = 1
    X = df[indepvars]

    reg = sm.OLS(Y, X).fit()
    if results != 0:
        print(reg.summary())

但请注意,虽然字符串插值可以“扩展”字符串,但这种方法不起作用,因为回归分析的目标函数不接受'weight, price, cons'这类统一字符串。

相反,您需要使用回归量定义列表:

predictors = ['weight', 'price', 'cons']
reg2('mpg', predictors, 0, df)

您还可以通过构建装饰器将此概念提升到新的水平:

def load_and_reg2(func):
    def wrapper(*args, **kwargs):

        print()
        print("Loading the dataset...")
        print()

        df = pd.read_stata('http://www.stata-press.com/data/r14/auto.dta')
        sumvars = df[['mpg', 'weight', 'price']].head()
        print(sumvars)
        print()

        func(*args, **kwargs, df = df)
        return func(*args, **kwargs, df = df)

        print()
        print("Doing any other stuff you like...")
        print()

        dfshape = df.shape
        print('Shape:', dfshape)

    return wrapper

并在你的reg2()函数中使用它:

@load_and_reg2
def reg2(depvar, indepvars, results, df):
    Y = df[depvar]
    df['cons'] = 1
    X = df[indepvars]

    reg = sm.OLS(Y, X).fit()
    if results != 0:
        print(reg.summary())
    return reg

这个例子可能非常简单,但展示了Python的强大功能:

In [7]: [predictors = ['weight', 'price', 'cons']
In [8]: reg2('mpg', predictors, 1)

Loading the dataset...

   mpg  weight  price
0   22    2930   4099
1   17    3350   4749
2   22    2640   3799
3   20    3250   4816
4   15    4080   7827

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                    mpg   R-squared:                       0.653
Model:                            OLS   Adj. R-squared:                  0.643
Method:                 Least Squares   F-statistic:                     66.85
Date:                                   Prob (F-statistic):           4.73e-17
Time:                                   Log-Likelihood:                -195.22
No. Observations:                  74   AIC:                             396.4
Df Residuals:                      71   BIC:                             403.3
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
weight        -0.0058      0.001     -9.421      0.000      -0.007      -0.005
price      -9.351e-05      0.000     -0.575      0.567      -0.000       0.000
cons          39.4397      1.622     24.322      0.000      36.206      42.673
==============================================================================
Omnibus:                       29.900   Durbin-Watson:                   2.347
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               60.190
Skew:                           1.422   Prob(JB):                     8.51e-14
Kurtosis:                       6.382   Cond. No.                     3.00e+04
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large,  3e+04. This might indicate that there are
strong multicollinearity or other numerical problems.

Doing any other stuff you like...

Shape: (74, 13)

正如您所看到的,装饰器进一步抽象出事物,但使用固定语法。

在Python Universe中, 字典在重用代码/结果中也起着重要作用。 例如,字典可以作为Stata的return空间的等价物来存储多个宏,标量等。

考虑我们的玩具装饰者load_and_reg2的略微改变的版本,它现在将单个对象保存在字典D并返回它:

def load_and_reg2(func):
    def wrapper(*args, **kwargs):

        D = {}

        print()   
        print("Loading the dataset...")
        print()

        df = pd.read_stata('http://www.stata-press.com/data/r14/auto.dta')
        sumvars = df[['mpg', 'weight', 'price']].head()
        D['sumvars'] = sumvars
        print(sumvars)
        print()

        D['reg2'] = func(*args, **kwargs, df)

        print()
        print("Doing any other stuff you like...")

        print()                     
        dfshape = df.shape
        D['dfshape'] = dfshape              
        print('Shape:', dfshape)

        return D    

    return wrapper

然后你可以轻松地做到:

In [9]: foo = reg2('mpg', predictors, 1)

In [10]: foo.keys()
Out[10]: dict_keys(['sumvars', 'reg2', 'dfshape'])

In [11]: foo['sumvars']
Out[11]: 
   mpg  weight  price
0   22    2930   4099
1   17    3350   4749
2   22    2640   3799
3   20    3250   4816
4   15    4080   7827

类可以以一些额外的复杂性为代价来引入进一步的灵活性:

class loadreg2return(object):
    def __init__(self, sumvars=None, reg2=None, dfshape=None):
        self.sumvars = sumvars
        self.reg2 = reg2
        self.dfshape = dfshape

def load_and_reg2(func):
    def wrapper(*args, **kwargs):

        print("Loading the dataset...")
        print()

        df = pd.read_stata('http://www.stata-press.com/data/r14/auto.dta')
        sumvars = df[['mpg', 'weight', 'price']].head()
        print(sumvars)
        print()

        reg2 = func(*args, **kwargs, df = df)

        print()
        print("Doing any other stuff you like...")

        print()                     
        dfshape = df.shape
        loadreg2return(dfshape = dfshape)            
        print('Shape:', dfshape)

        return loadreg2return(sumvars = sumvars, reg2 = reg2, dfshape = dfshape )

    return wrapper

这个版本的玩具装饰者返回:

In [12]: foo.dfshape
Out[12]: (74, 13)

In [13]: foo.sumvars
Out[13]: 
   mpg  weight  price
0   22    2930   4099
1   17    3350   4749
2   22    2640   3799
3   20    3250   4816
4   15    4080   7827

In [14]: foo.reg2.params
Out[14]: 
weight    -0.005818
price     -0.000094
cons      39.439656

dtype: float64

看起来你只想要***运算符来调用函数:

regargs = 'mpg', 'weight foreign price', 'y'
reg2(*regargs)

使用*将列表或元组扩展为位置参数,或使用**将字典扩展为需要它们的函数的关键字参数。

对于关键字示例,您需要稍微更改声明:

regargs = dict(depvar='mpg', covariates='weight foreign price', results='y')
reg2(**regargs)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM