教育装备采购网
第七届图书馆 体育教师课题研修班

【Stata专栏】如何在Stata16中调用Python

教育装备采购网 2019-07-24 13:22 围观4909次

  面对大数据时代,Stata16推出了Python接口,允许在Stata界面调用Python。为配合《高级计量经济学》课程的“编程专题”,本文将对Stata Function Interface(sfi)作简要介绍,感兴趣的同学可以适当尝试。

  说到软件交互,其实就是4个事情:

  如何在Stata中启动Python环境

  如何将Stata的数据类型转化为Python的数据类型

  如何将Python的数据类型转化为Stata的数据类型

  如何将Python函数封装在Stata命令中

  先说几句题外话。我个人认为,Stata16的这项新功能意义并不大。一方面,Python早就可以调用Stata了,我们完全可以将Stata的命令封装在Python命令中;另一方面,数据类型的转化完全可以通过数据集的导入导出来实现。正如我们经常做的,用Python爬一组数据,然后保存为Excel工作表,最后用Stata读取并建模。因此在我看来,Stata16提供Python接口,会将很多Stata铁粉引向免费的Python,但对同时掌握Stata和Python的用户却毫无激励。来都来了,我们简单看看这个接口吧。

1 启动Python环境

  1.1 配置Stata与Python的关联

  首先,你需要在电脑上同时安装好Stata和Python。如果你还没有安装Python,建议下载Anaconda,版本为3.X。地址如下:

  https://www.anaconda.com/distribution/

  假设我们将Anaconda安装在D盘根目录下,会发现Python软件的地址为

  ‪D:\Anaconda3\python.exe

  打开Stata16,在命令栏输入

set python_exec D:\Anaconda3\python.exe

  Stata和Python就算关联好了。

  尝试一下:在命令栏键入python,出现以下结果就算成功了。

. python
----------------------------------------------- python (type end to exit) ---------------
>>> 

  1.2 进入Python环境

  在Stata界面下进入Python环境的方式有3种:

  完全进入

  键入python可完全进入Python环境,命令提示符从.变为>>>。此后,我们可以自由输入Python代码,直到输入end命令退出该环境。举例如下:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> print('Hello NJUPT!')
Hello NJUPT!
>>> city = 'NJUPT'[:2]
>>> print('I LOVE', end=' '); print(city)
I LOVE NJ
>>> end
-----------------------------------------------------------------------------------------

  半完全进入

  键入python:可进入Python环境,但这种进入并不稳定,一旦出现错误就会回到Stata环境中。举例如下:

. python:
----------------------------------------------- python (type end to exit) ---------------
>>> print('I am a teacher.')
I am a teacher.
>>> print(1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
-----------------------------------------------------------------------------------------
r(7102);


  非完全进入

  在python:后直接键入一个或多个命令,可以在不跳出Stata环境的前提下,临时性地执行Python语法。举例如下:

. python: print('I Love You.'); print('I Love You, too.')
I Love You.
I Love You, too.

  非完全进入非常有用,能使我们在撰写Stata小程序时直接调用Python的方法。

  1.3 在Python环境下调用Stata

  当(半)完全地进入Python环境时,又如何临时调用Stata命令呢?很简单,使用stata:前缀即可。举例如下:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> stata: sysuse auto.dta, clear
(1978 Automobile Data)
>>> stata: regress price weight, nohead nocons
------------------------------------------------------------------------------
       price |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
------------- ----------------------------------------------------------------
      weight |   2.041977   .0926943    22.03   0.000     1.857238    2.226717
------------------------------------------------------------------------------
>>> end
-----------------------------------------------------------------------------------------

  1.4 数据类型不兼容问题

  刚拿到Stata16,我还无法完全摸清Stata和Python在数据类型上的兼容性,比如:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> a = 1 1
>>> stata: display a
a not found
r(111);
>>> stata: scalar x = a
>>> stata: display x
2
>>> end
-----------------------------------------------------------------------------------------

  为了保证代码执行的正确性,我们尽可能在两种软件的数据类型转换上做到“全手动”。下一节可以帮助我们了解这种转换的基本规律。

2 数据交互

  本节介绍如何在Stata的数据类型和Python的数据类型之间进行转换。其适用情境为:

  数据已经在Stata内存(数据编辑器)中,但想要使用Python的方法;比如,我们已经加载auto.dta数据集,但希望使用Python的matplotlib库绘制一个以length为横轴、weight为纵轴、price为尺寸的散点图,并保存为dpi为300的png格式。

  使用Python获取数据或运算出数据结果,但想要使用Stata的命令;比如,我们通过tushare获取财经数据,但希望使用Stata进行Garch(1,1)估计,求出长期波动率。

  当然更复杂的是两者间相互调用,一方的执行结果决定了另一方的执行内容,反之亦然。

  2.1 Stata Function Interface (sfi)

  首先必须明确,sfi是一个Python库,因此我们始终在Python环境下载入和使用它。sfi的文档在以下地址中:

  https://www.stata.com/python/api16/

  从功能(而非模块)上梳理SFI的命令,主要包括以下4类:

  创建数据表的命令,主要包括设置样本量和添加变量,形式上以add开头

  将Stata数据转化为Python数据的命令,形式上以get开头

  将Python数据转化为Stata数据的命令,形式上以store或set开头

  其他命令,比如删除变量、处理异常、管理内存等

  第4类命令其实很奇怪,我们完全不需要使用sfi库中的相关命令,转换之后使用Stata或Python自带的功能处理就好。因此,我们主要介绍前3类。

  2.2 add族

  当你希望将Python数据集转换为Stata数据集时,这一步非常重要。因为此时,Stata内存中什么也没有,没有数据、没有变量、甚至没有工作表;因此我们需要先告诉Stata,从Python转过来的数据集有怎样的“长”和“宽”,Stata才能准确接纳该数据集。

  假设我们使用tushare库获取了浦发银行的日线行情数据,我们必须先确定要将多长、多宽的数据放入Stata;本例中,我们希望放入全部的样本(索引)和2个变量(trade_date/close),确定工作表大小的代码如下:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> import tushare as ts
>>> tsToken = 'f***7'
>>> pro = ts.pro_api(tsToken)
>>> df = pro.daily(ts_code='600000.SH')
>>> df.shape
(4000, 11)
>>> end

  我们通过数据框的shape属性了解到df数据框中有4000行(样本)和11列(变量),根据我们的要求,最终进入Stata的是一个4000×2的数据集。接下来,我们就可以通过addObs和addVar*命令新建行列。

. python
----------------------------------------------- python (type end to exit) ---------------
>>> from sfi import Data       # 引入sfi.Data
>>> Data.addObs(len(df))       # 创建与df行数一致的样本量
>>> Data.addVarStrL('Date')    # 创建字符串变量Date
>>> Data.addVarFloat('Price')  # 创建浮点型变量Price
>>> end
-----------------------------------------------------------------------------------------

  打开数据编辑器,我们会看到工作表中已经有两个变量和4000行了,其中Date是空格,Price是缺失值符号.。其实,这两步完全可以在Stata环境下完成,使用Python环境的优势在于我们有len函数可以确定df数据框的样本量,这是一个动态过程。

  2.3 store族

  确定了工作表的长宽后,我们就可以使用store命令将Python数据存入Stata中。本例中,我们将df数据框中的trade_date列存入Stata的Date列,将df数据框中的close列存入Stata的Price列;操作如下:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> Data.store('Date',None,df['trade_date'])
>>> Data.store('Price',None,df['close'])
>>> end
-----------------------------------------------------------------------------------------

  我们来了解一下store命令的参数。store命令的形式为store(var, obs, val[, selectvar])。参数var表示目标列名称,可以是数值/字符串/列表/None;参数obs表示样本量,可以是数值/列表/None,None列示全部样本;参数val表示待存入的数据,要求是数组。selectvar是一个可选参数,默认为None,表示对存入变量的选取。需要特别注意的是obs选项,因为没有缺省值,我们不能省略None。

  2.4 get族

  get族命令用于Python读取Stata数据(和一些非数据内容)。根据读取的数据类型差异,我们分成Data、Scalar、Matrix和Macro这4种主要类型来讲:

  Data.get和Data.getAsDict

  因为Python是动态类型语言,因此不需要先确定数据的存储类型和名称。以读取auto数据集为例:

. python
----------------------------------------------- python (type end to exit) ---------------
>>> from sfi import Data
>>> lst = Data.get('price weight length')        # 列表形式
>>> lst[0]
[4099, 2930, 186]
>>> dct = Data.getAsDict('price weight length')  # 字典形式
>>> import pandas as pd
>>> df = pd.DataFrame(dct)                       # 转化为数据框
>>> df.head(1)
   price  weight  length
0   4099    2930     186
>>> end
-----------------------------------------------------------------------------------------

  get命令提取出的数据是列表形式,丢失了列标签;getAsDict命令提取出的数据是字典形式,保留了列标签(键)。我个人建议使用后者,并及时保存为数据框格式。此外,当我们只需要数据集中的单个值时,可以使用Data.getAt命令,该命令通过变量参数和索引参数确定唯一的位置并提取对应元素。

  Scalar.getValue和Scalar.getString

  除了数据集外,我们还会在Stata中使用一些“单值”,比如常数、结果、参数值等等。我们使用sfi.Scalar模块来读取这些内容。举例如下:

. scalar s = "I Love You."
. display s
I Love You.
. quietly regress price weight length
. display e(r2)
.34756307

. python
----------------------------------------------- python (type end to exit) ---------------
>>> from sfi import Scalar
>>> Scalar.getString('s')     # 提取字符串
'I Love You.'
>>> Scalar.getValue('e(r2)')  # 提取数值
0.3475630724239044
>>> end
-----------------------------------------------------------------------------------------

  当我们需要重复使用Stata命令时,Python迭代可能比Stata自己的循环效率更高,提取并记录单值就显得格外重要。

  Matrix.get

  当数据结果为矩阵时,我们使用Matrix.get命令实现提取。举例如下:(接上例回归结果)

. matrix list e(b)
e(b)[1,3]
        weight      length       _cons
y1   4.6990649  -97.960312   10386.541

. python
----------------------------------------------- python (type end to exit) ---------------
>>> from sfi import Matrix
>>> Matrix.get('e(b)')
[[4.699064878412987, -97.9603118181582, 10386.540540844977]]
>>> end
----------------------------------------------------------------------------------------- 

  单使用Matrix.get命令会丢失矩阵的行列名称,因此Stata还提供了Matrix.getColNames和Matrix.getRowNames来提取行列名称。与Data.getAt类似,我们也可以通过Matrix.getAt命令提取矩阵中的单个元素,注意该命令的参数有3个,分别是矩阵名、行和列。

  Macro.getLocal和Macro.getGlobal

  在Stata中,Macro被称为“宏”,分为局部宏(local)和全局宏(global)两种;宏名称在细分类中不能重复,但局部宏和全局宏的名称可以相同(实际上只是命名时相同,存储时并不同)。同样,我们可以通过Macro.getLocal和Macro.getGlobal获取宏。举例如下:

. local x 1 1
. display `x'
2

. python
----------------------------------------------- python (type end to exit) ---------------
>>> from sfi import Macro
>>> Macro.getLocal('x')          # 切记:宏是即用即解的
'1 1'
>>> Macro.getGlobal('e(model)')  # ereturn的宏是全局宏
'ols'
>>> end
-----------------------------------------------------------------------------------------

3 小结

  正如上文所言,我们的最终目的是将Python的方法封装到Stata程序中,或者将Stata的命令封装到Python函数中。当我们实现了数据类型的转换后,封装命令就一点也不难了。

  但以我刚接触的感受来讲,Stata16的SFI真的非常蠢,写到这里我竟一时间不知道如何解释下去:

  变量的长度不能自适应,我们必须先通过set obs或addobs来确定样本量

  Python的数据框(来自pandas)和Stata的数据集之间不能直接转换

  变量要先创建再填充,目标数据类型需要手动设置,缺少获取变量名称列表的函数

  缺少获取数字-文字对照表的函数,也没有提取全部命令结果(包括图形命令结果)的函数

  特别地,如果我们希望将Stata数据集完整的读入Python或反过来,我个人建议使用Excel工作表作中介。效率上差一点,但节约很多代码。举例如下:

. python // Stata-> Python
----------------------------------------------- python (type end to exit) ---------------
>>> import pandas as pd
>>> stata: sysuse auto.dta
(1978 Automobile Data)
>>> stata: export excel price weight length using "D:\auto.xlsx" if rep78!=., firstrow(variables) replace
>>> df = pd.read_excel(r'd:\auto.xlsx',header=0)
>>> df.head(1)
   price  weight  length
0   4099    2930     186
>>> end
-----------------------------------------------------------------------------------------

. python // Python -> Stata
----------------------------------------------- python (type end to exit) ---------------
>>> import tushare as ts
>>> import pandas as pd
>>> tsToken = 'f***7'
>>> pro = ts.pro_api(tsToken)
>>> df = pro.daily(ts_code='600000.SH')
>>> df.to_excel(r'd:\quotes.xlsx',header=True,index=False)
>>> stata: import excel "D:\quotes.xlsx", sheet("Sheet1") firstrow
(11 vars, 4,000 obs)
>>> end

-----------------------------------------------------------------------------------------

文章作者: 金融系程老师(微信公众号)


  最后,启发大家去读一读SFI的手册,我留下了set族命令没有介绍。这是一类在Python中设定Stata单值、暂元、矩阵等元素的命令,使用方法和get族非常类似,希望同学们有空去了解一下。

  在这愉快悠长假期里,小伙伴们兴高采烈的旅游、聚会、逛街、访学、晒娃、美食,并享受其中,还没有安排适当的学习计划吧!趁着假期的尾巴,想不想来一场光速学习充电之旅呢!

  第三届Stata用户大会 & Stata夏季训练营震撼来袭,顶配双男神|2 1模式,2019现场直击全程八天(含会议)Stata魔鬼训练营(机器学习 计量方法应用)。相约上海财经大学不见不散,感兴趣的小伙伴一起加入吧!


【Stata专栏】如何在Stata16中调用Python


点击进入北京友万信息科技有限公司展台查看更多 来源:教育装备采购网 作者:Uone-Tech 责任编辑:张肖 我要投稿
校体购终极页

相关阅读

版权与免责声明:

① 凡本网注明"来源:教育装备采购网"的所有作品,版权均属于教育装备采购网,未经本网授权不得转载、摘编或利用其它方式使用。已获本网授权的作品,应在授权范围内使用,并注明"来源:教育装备采购网"。违者本网将追究相关法律责任。

② 本网凡注明"来源:XXX(非本网)"的作品,均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,且不承担此类作品侵权行为的直接责任及连带责任。如其他媒体、网站或个人从本网下载使用,必须保留本网注明的"稿件来源",并自负版权等法律责任。

③ 如涉及作品内容、版权等问题,请在作品发表之日起两周内与本网联系,否则视为放弃相关权利。

校体购产品