[英]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宏的东西?
在Stata中普遍使用宏反映了不同的编程哲学。 与Python(一种面向对象的通用编程语言)不同,Stata的ado
语言(不是mata
)需要宏才能使其不仅仅是一种简单的脚本语言。
出于两个目的,宏几乎可以在Stata中的任何地方使用(即使在宏定义中):
使用宏,用户可以简化他们的代码,从而减少错误的可能性并保持整洁。 缺点是宏的使用呈现语言流的语法。
为了回答你的问题, 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.