<h3>用Python的方式来做。</h3>
<p>Stata中宏的广泛使用反映了一种不同的编程理念。
与Python不同,Python是一种面向对象的通用编程语言,
Stata的<code>ado</code>语言(不是<code>mata</code>)需要宏才能作为
不仅仅是一种简单的脚本语言。在</p>
<p>宏几乎可以在Stata中的任何地方使用(甚至在宏定义中),有两个目的:</p>
<ol>
<li>文本替换</li>
<li>表达式求值</li>
</ol>
<p>使用宏,用户可以简化他们的代码,这反过来又会减少
有可能出错并保持整洁。缺点是使用宏
呈现语言的语法流畅。在</p>
<p>要回答您的问题,<a href="http://pyexpander.sourceforge.net/" rel="noreferrer">Pyexpander</a>
在Python中提供了一些此类功能,但实际上它不是
代替。对于不同的用例,您将需要不同的方法来模拟
宏观扩张。与Stata相比,没有一个统一的方法在任何地方进行。在</p>
<p>我的建议是<em>熟悉Python的约定,而不是
试着用“Stata way”</em>编程。例如,记住
Stata中的局部宏和全局宏对应于Python(local)中的变量
在函数中,全局外部),而Stata中的变量对应于
<code>Pandas.Series</code>或<code>Pandas.DataFrame</code>的列。类似地,Stata <code>ado</code>
程序对应于Python中的函数。在</p>
<p>@g.d.d.c的答案中提供的解决方案可能是实现目标的一个很好的工具
有人想要什么。但是,如果您愿意,这里需要额外的步骤
重复使用你的代码。在</p>
<p>以你的玩具为例:</p>
<pre><code>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
</code></pre>
<p>假设您希望重用以下代码片段,但是
变量:</p>
^{pr2}$
<p>你怎么可能那样做?在</p>
<p>首先,创建一个<strong>函数</strong>:</p>
<pre><code>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())
</code></pre>
<p>但是,请注意,虽然字符串插值可以“扩展”字符串,但这里
这种方法行不通,因为回归分析的目标函数
不接受<code>'weight, price, cons'</code>类型的统一字符串。在</p>
<p>相反,您需要用回归函数定义一个列表:</p>
<pre><code>predictors = ['weight', 'price', 'cons']
reg2('mpg', predictors, 0, df)
</code></pre>
<p>您还可以通过构造<strong>装饰器将这个概念提升到下一个层次:</p>
<pre><code>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
</code></pre>
<p>并在<code>reg2()</code>函数中使用:</p>
<pre><code>@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
</code></pre>
<p>这个例子可能非常简单,但它展示了Python的强大功能:</p>
<pre><code>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)
</code></pre>
<p>如您所见,decorator进一步抽象了一些东西,但是使用了<em>固定的</em>语法。在</p>
<p>在Python世界中,<strong>字典</strong>和<strong>类</strong>在
重复使用代码/结果。例如,字典可以相当于
Stata的<code>return</code>空间,用于存储多个宏、标量等</p>
<p>考虑一下我们的玩具装饰器<code>load_and_reg2</code>稍作修改的版本,它
现在将单个对象保存在字典<code>D</code>中并返回它:</p>
<pre><code>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
</code></pre>
<p>然后您可以轻松地执行以下操作:</p>
<pre><code>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
</code></pre>
<p>类可以以代价引入更多的灵活性
一些额外的复杂性:</p>
<pre><code>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
</code></pre>
<p>此版本的玩具装饰器返回:</p>
<pre><code>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
</code></pre>