用Python的方式来做。

Stata中宏的广泛使用反映了一种不同的编程理念。

与Python不同,Python是一种面向对象的通用编程语言,

Stata的ado语言(不是mata)需要宏才能作为不仅仅是一种简单的脚本语言。在宏几乎可以在Stata中的任何地方使用(甚至在宏定义中),有两个目的:文本替换表达式求值使用宏,用户可以简化他们的代码,这反过来又会减少有可能出错并保持整洁。缺点是使用宏呈现语言的语法流畅。在要回答您的问题,Pyexpander

在Python中提供了一些此类功能,但实际上它不是代替。对于不同的用例,您将需要不同的方法来模拟

宏观扩张。与Stata相比,没有一个统一的方法在任何地方进行。在我的建议是熟悉Python的约定,而不是

试着用“Stata way”编程。例如,记住Stata中的局部宏和全局宏对应于Python(local)中的变量在函数中,全局外部),而Stata中的变量对应于Pandas.Series或Pandas.DataFrame的列。类似地,Stata ado程序对应于Python中的函数。在@g.d.d.c的答案中提供的解决方案可能是实现目标的一个很好的工具有人想要什么。但是,如果您愿意,这里需要额外的步骤重复使用你的代码。

在以你的玩具为例:

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

假设您希望重用以下代码片段,但是

变量:

^{pr2}$

你怎么可能那样做?在

首先,创建一个函数:

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)

如您所见,decorator进一步抽象了一些东西,但是使用了固定的语法。在在Python世界中,字典和类在

重复使用代码/结果。例如,字典可以相当于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