MacBook技巧:如果需要复制路径,在finder里,对选中的文件,cmd+opt+c,就复制到剪贴板了。

参考书籍:陈传波-stata软件教程。

0 简介

Stata 统计软件包是目前世界上最著名的统计软件之一,与SAS、SPSS 一起被并称为三大权威软件。它广泛的应用于经济、教育、人口、政治学、社会学、医学、药学、工矿、农林等学科领域,同时具有数据管理软件、统计分析软件、绘图软件、矩阵计算软件和程序语言的特点,几乎可以完成全部复杂的统计分析工作。其功能非常强大且操作简单、使用灵活、易学易用、运行速度极快,在许多方面别具一格。

Stata 的另一个特点是他的许多高级统计模块均是编程人员用宏语言写成的程序文件(ADO 文件),这些文件可以自行修改、添加和下载。用户可随时到Stata 网站寻找并下载最新的升级文件。这一特点使得STATA 始终处于统计分析方法发展的最前沿,用户几乎总是能很快找到最新统计算法的Stata 程序版本,而这也使得Stata 自身成了几大统计软件中升级最多、最频繁的一个。

几个主要的网站:

0.1 获得帮助

help //显示出STATA 所有帮助内容的目录结构。
help summarize //如果输入具体的命令,则只显示该命令的帮助

也可以通过菜单式的点选方式获得帮助: Help>>stata command…在弹出的对话框中输入:summarize 然后回车,得到与help summarize 同样的结果。

网络帮助可以采用如下命令获得

findit scat3
search scat3,net

1. 基本操作

1.1 数据导入与输出

导入数据

一般做实证分析使用的是excel中的数据,其后缀名为.xls,需要将其修改为.csv

insheet using name.csv, clear
use name.dta,clear

当数据中某个变量的位数特别长或者对导入数据的精度要求很高的时候,需要在该命令后面加double选项。

insheet using name.csv, double clear

系统自带文件和网络文件的打开

sysuse auto,clear
webuse nlswork,clear //从STATA 官方数据库获取数据

删除重复变量

sort var1 var2
duplicatesdrop var1 var2, force

合并数据

use data1, clear
merge m:m var1 var2 using data2
drop if _merge==2
drop if _merge==1
drop _merge

输出为excel文件

export excel using "mywide.xls",firstrow(variable) replace

结果输出

//安装 
ssc install estout, replace
//单个回归
reg y x
esttab using name.rtf, compress nogap r2 ar2 star(* 0.1 ** 0.05 *** 0.01)
//多个回归一起
reg y x1 
est store m1
reg y x2
est store m2
esttab m1 m2 using /juncker/desktop/name.rtf, compress nogap r2 ar2 star(* 0.1 ** 0.05 *** 0.01) //第一种
esttab re1 re2 re3 re4 using table10.rtf,se mtitles star(* 0.1 ** 0.05 *** 0.01) b(%4.3f) se(%4.3f) r2(%4.3f)//第二种

1.1a 生成新数据的方法

生成新数据:生成新的数据x(x=1,2,…,1000);y=x+100

clear 
set obs 1000
gen x = _n
gen y = x+100

1.1b 数据类型转化

字符型转化为数字型

destring, replace //全部转换为数值型,replace 表示将原来的变量(值)更新
destring date, replace ignore(" ") //忽略空格,然后转换,注意这里的" "中间有一个空格,不是""。
destring price percent, gen(price2 percent2) ignore("$,%") ////注意到price2 前面的$号消失,percent2 后面的%号消失

数字型转化为字符型

webuse tostring,clear 
des //注意到month 为字符型,而年和日为数值型
//由于month 为字符型,年和日为数值型,不同类型不能相加
tostring year day,replace //将年和日转化为字符型
gen date1 = month + "/" + day + "/" + year
list
gen date2 = date(date1,"MDY") //date()为日期函数,它以1960年1月1日为第0天,计算从那天起直到括号中指定的某天date1一共过了多少天。”mdy”指定date1的排列顺序,这里是按照月日年的顺序来表示日期。
list

1.1c gen和egen的区别

egen命令相对复杂一些,对于变量包含重复序列的大型数据库非常有用。它能生成一些“gen”命令无法生成的变量。egen 的特点是它更强大的函数功能。 gen 可以支持一些函数, egen 支持额外的函数。例如可以生成wagesum为每个人的工资和,以及生成wagemedian为工资的中位数(median),wagemax为工资的最大值。

gen educsqr=educ^2
egen wagesum = sum(wage)
egen wagemedian = median(wage)
egen wagemax = max(wage)
//更复杂的如想产生一个变量“wagemax”为相同教育水平里的最高工资。
egen wagemaxeduc = max(wage),by(educ)

再举个简单的例子:

clear 
set obs 5
gen x = _n
gen y = sum(x)
egen z = sum(x)

结果如下

x y z
1 1 1 15
2 2 3 15
3 3 6 15
4 4 10 15
5 5 15 15

例子:通过多列求平均,生成新列。

egen testmean = rowmean(test1 test2)
list testmean test1 test2

1.2 描述性统计

格式化生成结果:

tabstat var1 var2, stat(n min mean median p25 p75 max sd),  if groupvar==0 or 1
//输出到word中:
logout, save(name) word replace: tabstat var, stat(n min mean p50 max sd) col(stat)f(%9.2g)

再举个简单的例子,帮助理解sum函数生成的变量的样子(按某列样本累加,因此样本的排序就很重要!):

clear 
set obs 5
gen x = _n
gen y = sum(x)

结果如下

x y
1 1 1
2 2 3
3 3 6
4 4 10
5 5 15

1.2a 画图

use auto,clear
sum weight	///
price	///
length	//求重量、价格、长度的平均值
scatter price weight //绘价格和重量的散点图

对较长的命令或者为便于阅读,将一行命令写成几行时,用///来分开

1.3 统计检验

生成虚拟变量

tab year, gen(year)
tab industry, gen(industry)

数据缩尾处理

findit winsor2
//之后安装
winsor2 varname, replace cut(1 99)

异方差检验

//怀特检验
ssc install whitetst
reg y x1 x2
estat imtest, white
//处理:“OLS+稳健标准差”
reg y x1 x2 x3, robust

DW检验

gen id=_n
tsset id
estat dwatson

计算两个日期之间的间隔天数

gen td=date(trading_date,'YMD')
gen ed=date(eventdate,'YMD')
form td ed %td
gen d=ed-td

生成滞后、差分数据

tsset code year
gen newvarname=l.varname
gen newvarname=d.varname

多重共线检验之方差膨胀因子

reg y x1 x2 x3
vif

多重共线修正之逐步回归

stepwise, pe(0.1): reg y x

检验是否遗漏高次项

reg y x
estat ovtest
//或者
estat ovtest, rhs

样本检验

//两样本均值T检验
ttest var, by(groupvar)
//两样本中位数Z检验
ranksum var, by(groupvar)

1.4 数据排序

1.4.1 sort

如果sort命令中只包含一个变量名,无论变量类型是数值还是字符串,stata都会以此变量对数据进行升序排序。

sysuse auto,clear
sort mpg
list

观测值相同的排序:还是对mpg进行排序,但我们加上一个小尾巴,结果就会满足我们的需求:

sysuse auto,clear
sort mpg,stable
list

如果命令包含有两个或者更多变量名的varlist,数据将以如下方式排序:

键入sort命令,按第一个变量对观测值进行排序,然后,对于在第一个变量有相同取值的观测值,stata按第二个变量对这些观测值进行排序,等等。

sysuse auto,clear
sort mpg length
list

在使用 sort命令之后,数据集将被标记为是按那些变量排序的,但如果希望保存这一新排序次序的话,需要将此新的数据集保存到硬盘里

1.4.2 gsort

基本语法:

gsort [+|-] varname [[+|-] varname ...] [, generate(newvar) mfirst]

其中需要说明的内容有两点:

  • [+]表示按升序排列,这也是Stata默认的排列方式,[-]表示按降序排列;
  • generate(newvar)表示排序之后生成新的变量,mfirst表示将缺失值排在最前面。
sysuse auto,clear
gsort -make
list in 1/10

1.5 分类操作

例子1:有一个变量foreign,该变量表示某个车是进口车(1 Foreign)还是国产车(0 Domestic)。如果需要分别知道国产车和进口车的价格和重量,可以采用分类操作来求得,

sysuse auto,clear
by foreign: sum price weight

可能犯的错

sort price
by foreign: sum price weight

系统提示没有排序,这是因为by varlist 在执行时要求内存中的数据是按照by后面的变量排序的。当我们用sort price 重新排序后,就打乱了原来按照foreign 的排序,所以出现了错误提示。更正的办法是:

sort foreign
by foreign: sum price weight

或者简化代码:

by foreign, sort: sum price weight

例子2:

clear
set obs 5
input x y
1 1.1
1 1.2
1 1.3
2 2.1
2 2.2
end
gen n = _n
gen N = _N
gen z = y[1]
export excel using "mydata.xls",firstrow(variable) replace

生成的数据如下:

x y n N z
1 1 1 1 5 1
2 1 1 2 5 1
3 1 1 3 5 1
4 2 2 4 5 1
5 2 2 5 5 1
by x, sort: gen n1 = _n //先根据x分组,n1对应于每一组数据对应的位置
by x, sort: gen N1 = _N //先根据x分组,N1是每一组数据的总数
by x, sort: gen z1 = y[1] //先根据x分组,z1是y每一组第一个值

1.5a 生成虚拟变量的一个方法

cut()将连续的数值,转换为区间的分类变量。先举个简单的例子:[3000, 7500)=便宜, [7500, 12000)=适中, [12000, 165000)=贵,共3个类别

sysuse auto,clear
egen price_category = cut(price), at(3000,7140,12000,16500) label //这里分成了[3000, 7500), [7500, 12000), [12000, 165000) 共3个类别
list price price_category
tab price price_category

从tab结果来看,实际上生成了标记类别的变量,似乎可以往虚拟变量那个方向考虑。

Price_category
price 3000- 7500- 12000- Total
3299 1 0 0 1
3667 1 0 0 1
3799 1 0 0 1
3955 1 0 0 1
3984 1 0 0 1
4082 1 0 0 1
4099 1 0 0 1
4453 1 0 0 1
4504 1 0 0 1
4749 1 0 0 1
4816 1 0 0 1
5104 1 0 0 1
5189 1 0 0 1
5705 1 0 0 1
5788 1 0 0 1
7827 0 1 0 1
10372 0 1 0 1
11385 0 1 0 1
14500 0 0 1 1
15906 0 0 1 1
Total 15 3 2 20

通过recode命令,对分类型变量重新编码

tab price_category, nolabel
price_categ
ory Freq. Percent Cum.
0 59 79.73 79.73
1 10 13.51 93.24
2 5 6.76 100.00
Total 74 100.00
recode price_category (0=1) (1=2) (2=3)
tab price_category, nolabel
tab price_category

1.5b 将分类编码进行数字编码(未解决)

sysuse auto,clear
encode foreign, gen(foreign_id)
label list foreign_id

1.5c 取某个具体的值作为列分组的值

生成新变量,取分组的第一个或者一个取值为分组的取值。

sort docid
by docid: gen first_age = age[1] //取分组的第一个值为分组的取值
by docid: gen lag_age = age[_n-1] //取分组内上一个位置的取值
by docid: gen last_age = age[_N] //去分组的最后一个值为分组的组织
docid age first_age lag_age last_age
1 1-1 1 1 . 4
2 1-1 2 1 1 4
3 1-1 3 1 2 4
4 1-1 4 1 3 4
5 1-2 5 5 . 8
6 1-2 6 5 5 8
7 1-2 7 5 6 8
8 1-2 8 5 7 8
9 1-3 9 9. . 11
10 1-3 10 9 9 11
11 1-3 11 9 10 11

1.6 条件表达式与范围筛选

若只想查看国产车的品牌和价格,则加入筛选条件

sysuse auto,clear
list make price if foreign==0

要计算较低的前10台车的平均价格,则要先按价格排序,然后仅对前10个车的价格求平均值。

sysuse auto,clear
sort price
sum price in 1/10

要计算较高的前10台车的平均价格,则要先按价格排序,然后仅对前10个车的价格求平均值。

sysuse auto,clear
gsort -price
sum price in 1/10

要计算前10台车中的国产车的平均价格,则可将范围和条件筛选联合使用。

sum price in 1/10 if foreign==0

注意:in和by不能一起使用。

1.7 加权weight

下表是2005 年湖北省高考640 分及以上成绩一分一段的人数统计,第一列score为高考分数,第二列num为该分数段的人数。现在我们要求640分及以上考生的平均分数。

score num
650 193
649 26
648 23
647 16
646 21
645 26
644 32
643 23
642 38
641 29
640 38

那么如何在stata中生成这两列数据呢?参考如下代码:

clear
set obs 11
gen score = 651-_n

可以使用代码建立新变量num输入数据

input str10 num

然后逐个数据输入。【如果中途要结束,直接输入代码end

然后计算加权平均分。

sum score [weight=num]

1.8 其他可选项

list price in 1/30, sep(10) //每10个观察值之间加一横线
list price in 10/30, sep(2)
list price, nohead //不要表头

1.(n-2) 多行编辑

VS Code 提供了多种多行编辑的快捷键,可以大大提高编码效率。以下是常用的几个快捷键:

  1. Alt + 鼠标左键拖动:可以同时选中多个位置进行编辑。
  2. Ctrl + Alt + 方向键上/下:可以在选中多行的情况下在上方或下方添加光标。
  3. Ctrl + Shift + L:可以选中所有与当前选中单词相同的单词,方便一次性修改。
  4. Shift + Alt + I:可以在选中多行的情况下在行尾插入光标,方便同时编辑多行。
  5. Ctrl + Shift + Alt + 方向键上/下:可以在选中多行的情况下复制并插入多个光标。

1.(n-1) 四则运算、函数运算

display 4+8
di 4+8
di 10/2
di 4^2
di exp(1)
di ln(1) //stata中ln和log是一个函数!
di sqrt(9)

常用函数

函数 含义 举例
数值型函数 abs(x)
comb(n,k) 从n中取k个组合 comb(10,2) =45
exp(x)
fill() 自动填充数据
int(x) 取整 int(5.6)=5,int(-5.2)=-5
ln(x)
log10(x)
mod(x,y) 模运算
round(x) 四舍五入
sqrt(x)
sum(x)
随机函数 uniform() 均匀分布随机数
invnormal(uniform()) 标准正态分布随机数
字符函数 real(s) 字符型转化为数值型
string(n)
substr(s,n1,n2) 从s的第n1个字符开始,截取n2个字符 substr(“family”,3,2) = mi
这个不行! word(s,n) 返回s的第n个字符 word(“family”,4)=i
系统变量 _n 当前观察值的序号
_N 共有多少观察值
_pi 圆周率

分组函数

clear
input a b
1 0
0 0
1 1
0 1
0 0
1 .
. 0
end

使用分组函数:

egen ab = group(a b) //按a 和b 来进行交叉分组,a=0,b=0 为第一组,…,a=1,b=1 为第四组,缺失值不参与分组
egen ab2 = group(a b),missing //将缺失的组当作另外的一组

生成范围变量

clear
set obs 100
gen age = _n  //生成一个假设的年龄变量age,依次取1,2,…,100
recode age (min/30=1) (30/60=2) (60/max=3),gen(agegrp) //生成新的分组变量agegrp,当年龄age 在30 及以下时取值为1,30 到60 为2,60 以上为3

1.n 几个环境设置

1.n.1 设置屏幕滚动

在列示1 到1000 之前,若先设置set more off,则屏幕不停止;反之set more on会使显示停止。

set more off
list
set more on 
list
q

1.n.2 设置内存大小

memory //查看内存使用情况
set memory 10m //设置内存

1.n.3 设置文件存取路径

cd d:/stata17 //定位数据的位置
dir //道当前路径下有哪些文件
mkdir d:/mydata //想在D盘的根目录下创建一个新的文件夹mydata来存放数据文件
cd d:/mydata

1.n.4 错误提示

list myvar

上述命令试图显示变量myvar,但是结果窗口仅出现如下的显示

variable myvar not found
r(111);

红色信息表明,没有找到一个叫myvar的变量,的确,我们的数据中并没有这个变量。list 巧妇难为无米之炊。红色信息下面还有一个天兰色的r(111),用鼠标点击,即可弹进一个帮助信息框,给出错误的更详尽解释。

1a 流程语句

1a.1 循环

capture drop count5
program count5
local i=1
while `i'<=5{
    display `i'
    local i = `i'+1
}
end

forvalues

更简洁的写法:

forvalues i =1/5{
    display `i'
}

步长为负

forvalues i=4 (-0.2) 0{
    display `i'
}

求和

scalar s=0
forvalue i=1/100{
    scalar s = s+`i'
}
scalar list s

foreach

将student.dta, economy.dta, math.dta 纵向拼接起来

use student,clear
foreach file in economy math{
    append using "`file'"
}

或者

local flist economy math //先将文件名赋于宏flist
foreach file in `flist'{
    append using "`file'"
}

(按项循环):逐行显示粮食(rice wheat flax maize)和货币(Dollar Lira Pound RMB)

local grains "rice wheat flax maize"
foreach x of local grains{
    di "`x'"
}
global money "Dollar Lira Pound RMB"
foreach y of global money{
    di "`y'"
}

(生成新变量):生成五个新变量b1,b2,b3,b4,b5,每个变量都是均匀分布随机数

clear 
set obs 10
foreach v of newlist b1-b5{
    gen `v' = uniform()
}

(按数值循环):逐行显示1 2 3 4 8 105

foreach num of numlist 1/4 8 105{
    di `num'
}

1b 命令小结

需求帮助
help 帮助
search 网络寻求帮助
进入某路径
cd
设定内存
set memory 20m 设置STATA 的内存空间为20m
打开和保存数据
clear 清空内存
use 打开stata格式的数据文件
save 保存内存中的数据
导入数据
input
edit
infile
insheet
重整数据
append 将有相同结果的数据纵向拼接(观察值拼接)
merge 将两个数据文件横向拼接
xpose 数据转置
reshape
generate 生成新的数据
egen 生成新的数据
rename 变量重命令
drop 删除变量或观察值
keep 保留变量或观察值
sort 观察值按从小到大顺序重新排列
order 变量顺序的重新排列
encode 数值型数据转换为字符型数据
decode 字符型数据转换为数值型数据
by 分类操作
报告数据
describe 总体展示数据情况
codebook 展示数据库中的每个变量情况
list 列示内存中的数据
count 报告共有多少观察值
inspect 报告变量的分布
table 数据列表
tabulate 联列表
显示和保存输出结果
display 显示计算结果
log 将输出结果存放入结果文件

1c 标签数据:label

命令 命令解释 用法示例
pwd 显示当前路径 pwd
dir 列示当前路径所有文件 dir
mkdir 在当前路径下创建一个新的文件夹 mkdir d:/mydata
label 给数据/变量/变量值增加标注签说明
label data 标签数据 label data “XX表”
label var 标签变量 label var name “姓名”
label value
label define
标签变量值 label values gender genderlb
label define genderlb 1"男"0"女"
note 为数据加注额外说明 note: 10月8日的数据
list 列示内存中的数据 list id name
save 保存数据 save mydata, replace
erase 删除数据文件 erase mydata.dta,replace

例子:原始数据:

id name gender minority economy math
1 John 1 1 40 68
2 Chris 1 2 80 52
3 Jack 0 2 90 76
4 Huang 0 2 43 90
5 Tom 0 3 70 96
6 Han 1 1 53 85
7 Phillip 0 2 85 36
8 Jin 1 2 95 65

为避免时间太长,忘记变量的含义,我们可以用label 命令来标记。该命令可以用来标记数据文件,如将文件取名为“2007年秋5632班学习成绩单”

label data “2007年秋5632班学习成绩单”

在文件处理过程中加注说明,命令为notes

note: 200796日由任我行创建该数据
note //下一次打开数据,要查看创建和数据处理的说明时,直接键入

也可以用label 命令来标记变量,如将id 标记为“学号”

label var id "学号"
label var gender “性别 1=2=女”

还可以标记变量的取值。注意要按以下两步来操作:

label define genderlb 1 "男" 0 "女"
list //注意此时gender 变量显示的值为0 或1
label values gender genderlb ////该命令仅仅是显示的变化,实质不变
list 
//注意此时gender 变量显示的值为男或女
label define minoritylb 1"汉族" 2 "少数民族"
label values minority minoritylb
list

定义完汉族和少数民族后发现还有些学生的民族是不知道的(原始值为 3),但是下面代码会报错

label define minoritylb 3 "不知道"

label minoritylb already defined,因为minoritylb 已经存在并被定义,我们需要加上选项,add

label define minoritylb 3 "不知道", add
list

下面代码依然会报错

label define minoritylb 3 "don’t know", add

因为3 已被定义,这次不是增加而是修改,所以选项为,modify

label define minoritylb 3 "don’t know", modify

标签的显示与删除

label dir //显示标签
label list //显示标签的赋值含义
label drop minoritylb //删除标签

2. 数据拆分与合并

  • 数据拆分
    1. 数据横向拆分—— keep& drop
    2. 数据纵向拆分—— keep& drop
    3. 一步到位保存数据子集—— savesome
  • 数据合并
    1. 数据的横向合并—— merge
    2. 数据的纵向合并—— append
    3. 对多个 csv文件纵向合并—— csvconvert
    4. 将多列数据转换成一列数据:stack stack a b c d, into(e f)
  • 转置:xpose

2.1 长宽数据转换—— reshape命令

  • 宽数据转为长数据
  • 长数据转为宽数据

数据文件下载:地址

2.2 数据拆分

如果把内存中的数据集视为一个矩阵,则我们对数据的基本操作包括两类:删除列或删除行。对于 Stata 而言,命令的主要操作对象是变量 (矩阵的列),而有些时候我们也需要删除特定的观察值 (矩阵的行)。这些操作都可以配合使用 dropkeep 命令来实现。

2.2.1 删除\保留变量:数据的横向拆分

原始数据有时包含过多的变量,但在实际应用中可能根据需要将原始数据拆分为不同的数据表,这时就要实现数据的横向拆分。数据的横向拆分用到的两个命令为 dropkeep

Stata 范例:

sysuse "auto.dta", clear
drop weight length
save "d:\data\auto_sim01.dta", replace

我们调入数据后,使用 drop 命令删除了两个变量,进而把处理后的数据文件另存到 D:\data 文件夹中。若该文件夹下已经存在一个名称为 auto_sim01.dta 则自动覆盖之,这是 replace 选项的作用。

按照上述思路,也就不难理解如下命令的含义了:

sysuse "auto.dta", clear
keep make price mpg rep78 foreign
save "d:\data\auto_sim02.dta", replace

特别说明: 一般而言,除非数据文件非常大导致每次调入耗时较长,我们很少另存数据文件。我们会将主要的修改动作都保留于 dofile 中。每次分析时,只需修改 dofile 或执行 dofile 中的特定语句即可实现对子样本的处理。毕竟,dofile 本质上是文本文件,文件大小通常不过几十k。

2.2.2 删除\保留观察值:数据的纵向拆分

原始数据有时包含过多的样本观测值,但在实际应用中可能根据需要将其按某种特征拆分为不同的数据表,这是就要实现数据的纵向拆分。此时,仍然可以使用 dropkeep 命令。

例如将 auto.dta 数据文件拆分为两个数据文件:auto_domestic.dtaauto_foreign.dta,操作如下:

sysuse "auto.dta", clear
keep if foreign==0
save auto_domestic.dta, replace 
sysuse "auto.dta", clear
keep if foreign==1
save auto_foreign.dta, replace

2.2.3 一步到位保存数据子集: savesome 命令

通过上述范例可以看出,使用 Stata 自带的 keepdrop 命令可以快捷地删除变量或观察值,但在命令写法上较为繁琐。我们可以使用外部命令 savesome 来提高效率 (该命令是 Stata 官方命令 save 的扩展版):

  • 安装程序文件:
ssc install savesome, replace

在命令窗口中输入 help savesome 可以查看该命令的帮助文件,其语法格式如下:

savesome [varlist] [if exp] [in range] using filename [, old save_options]

其中,

  • using filename 表示要保存的子集文件名及文件路径;
  • old 是较为重要的选项,可以将数据保存为较低版本的文件格式,如 stata15 用户可以将数据另存为在 stata14 或以下版本中的打开的数据文件。类似的命令还有 Stata 官方命令 saveold

对于前文提到的例子,我们可以使用 savesome 来实现相同的功能:

sysuse "auto.dta", clearkeep make price mpg rep78 foreignsave "d:\data\auto_sim02.dta", replace

等价于

sysuse "auto.dta", clear
savesome make price mpg rep78 foreign /// using "d:\data\auto_sim02.dta", replace

评论: 凭心而论,笔者更喜欢前一种方式。虽然多写了一行命令,但思路清晰,也便于记忆。

Stata 范例 2:

sysuse "auto.dta", clear
keep if foreign==0
save auto_domestic.dta, replace 

等价于:

sysuse "auto.dta", clear
savesome if foreign==0 using auto_domestic.dta, replace 

2.4 数据合并

2.4.1 数据的横向合并

数据的横向合并是横向拆分的逆操作,但是其要比拆分复杂。对于时间序列资料而言,要保证同一时点的两个变量的观察值对接到同一行;而对于界面个体资料而言,要保证同一个人的年龄数据与该人的收入数据在同一行。而对于面板数据资料,则需数据中有两个变量能够唯一标示每一行观察值,以保证 A 数据文件中的 “张三疯-2016” 与 B 数据文件中的 “张三疯-2016” 处于同一行。合并所使用的命令语句为 merge,具体语句如下所示:

merge [varlist] using filename [filename ...] [, options]

merge为合并的命令语句, [varlist]代表合并进去的新变量, using filename指的是所要与原文件合并的文件路径, options包含较多的功能,下表显示了其具体内容。

keep(varlist) 只保留filename中特定的变量
_merge(newvar) 合并之后生成新变量,默认名称为_merge
nolabel 不要复制flename中所定义的标签
nonotes 不要复制filename中所定义的注释
update 用flename中的数据代替内存中的缺失值。
replace 用flename 中的数据代替内存中的非缺失值。
nokeep 删除数据库中不能匹配的观测值
nosummary 删除summary变量
unique 匹配变量在原文件与合并文件中都是唯一的。
unigmaster 匹配变量在原文件中必须是唯一的
uniqusing 匹配变量在合并文件中必须是唯一的

举例:利用横向拆分实验中生成的数据文件 waterinputwateroutput实现数据的横向合并,匹配变量为 year,生成新的数据文件命名为 waternew。这个操作的命令为:

use c:\data\wateroutput, clear
sort year //按year排序
save c:\data\wateroutput, replace //重新保存一下
use c:\data\waterinput, clear //打开新的数据文件
sort year //按year排序
merge year using c:\data\wateroutput //以year为关联,将两个表合并
save c:\data\waternew, replace

在以上命令语句中,

  • 第一个命令语句实现了 wateroutput数据文件的打开
  • 第二个命令语句将文件按年份变量进行排序
  • 第三个命令语句保存了排序之后的数据文件
  • 第四个命令语句实现了 waterinput数据文件的打开
  • 第五个命令语句将此数据按年份变量进行排序
  • 第六个命令语句按年份变量将 wateroutput文件合并到 waterinput文件中
  • 第七个命令语句保存合并之后的数据文件。

2.4.2 数据的纵向合并

数据的纵向合并为数据纵向拆分的逆操作,使用的主要命令为 append命令,具体语句如下:

append using filename [, options] 

在这个命令语句中, append是进行纵向合并的命令语句, using filename是进行纵向合并的文件路径, [, options]的内容与 merge相似,但更为简化。

例如,利用纵向拆分实验中生成的数据文 domesticautoforeignauto实现数据的纵向合并,生成的数据文件命名为 usaautonew。这个操作的命令为:

use c:\data\domesticauto, clear
append using c:\data\foreignauto
save c:\data\usaautonew, replace

在以上命令中,第一个命令语句打开了原始数据文件,第二个命令将 foreignauto文件合并到 domesticauto文件中,第三个命令语句存储了合并后的数据文件。

2.4.3 一次合并多个csv文件—— csvconvert

csvconvert 命令用于将多个 csv格式文件合并为一个 .dta格式文件,比较适合处理具有时间周期性特点的变量。命令:

csvconvert input_directory, replace [options] 

该命令有三个参数:

参数名 功能
output_file(file_name) 设置输出文件名
output_dir(output_directory) 设置输出路径
input_file(.csv file list) 选择要合并的文件

命令下载:

help csvconvert

以命令配套的四个世界银行文件为例,首先看文件结构

dir C:\Uers\Administrator\Desktop\stata学习文件\worldbank\*.csv
Country Name Country Code Year YearCode GDP (current US$) Population, total
United States USA 2010 YR2010 1. 46E+13 309050816
United Kingdom GBR 2010 YR2010 2.25E+12 62218761
Canada CAN 2010 YR2010 1.57E+12 34108752

使用 csvconvert命令将四个年度数据纵向合并

csvconvert C:\Users\Administrator\Desktop\stata学习文件\worldbank, replace
countryname countrycode year yearcode gdpcurrentus population~l _csvfile
1 United States USA 2010 YR2010 1.458e+13 309050816 wb2010. csv
2 United Kingdom GBR 2010 YR2010 2.246e+12 62218761 wb2010. csv
3 Canada CAN 2010 YR2010 1.574e+12 34108752 wb2010. csv
4 United States USA 2009 YR2009 1.404e+13 307007000 wb2009. csv
5 United Kingdom GBR 2009 YR2009 2.173e+122 61801570 wb2009。 csv
6 Canada CAN 2009 YR2009 1.336e+12 33739900 wb2009. Csv
7 United States USA 2008 YR2008 1.430e+13 304375000 wb2008. Csv
8 United Kingdom GBR 2008 YR2008 2.657e+12 61393521 wb2008. Csv
9 Canada CAN 2008 YR2008 1.499e+12 33311400 wb2008. Csv
10 United States USA 2007 YR2007 1.400e+13 301580000 wb2007. csv
11 United Kingdom GBR 2007 YR2007 2.811e+12 60986649 wb2007. csv
12 Canada CAN 2007 YR2007 1.424e+12 32976000 wb2007. csv

要合并的四个子文件必须在同一个文件夹中,默认情况下, csvconvert命令会合并文件夹中所有文件 ,可以用 note 命令核对所合并的文件情况 .用 input_file参数选择所有合并的文件名,在此,我们只选择2008年度和2009年度的数据

csvconvert C:\Users\Administrator\Desktop\stata学习文件\worldbank, replace input_file(wb2008.csv wb2009.csv)

2.5 数据重整

举个例子更好理解:数据集mywide.dta共有六个变量,其中后四个变量分别为2003年和2004年的数据成绩和经济学成绩,现要求将数据转化为mylong.dta的格式,将年份单独做成变量,数学和经济学成绩则成为两个单独变量。

id name math2003 math2004 economy2003 economy2004
1 John 40 13 68 55
2 Chris 80 64 52 87
3 Jack 90 55 76 25
4 Huang 43 60 90 4
5 Tom 70 68 96 42
6 Han 53 10 85 89
7 Phillip 85 61 36 52
8 Jin 95 6 65 84

想要转化为如下格式:

id name year math economy
1 John 2003 40 68
2 John 2004 13 55
3 Chris 2003 80 52
4 Chris 2004 64 87
5 Jack 2003 90 76
6 Jack 2004 55 25
7 Huang 2003 43 90
8 Huang 2004 60 4
9 Tom 2003 70 96
10 Tom 2004 68 42
11 Han 2003 53 85
12 Han 2004 10 89
13 Phillip 2003 85 36
14 Phillip 2004 61 52
15 Jin 2003 95 65
16 Jin 2004 6 84

先输入数据

clear
set obs 8
gen id = _n
input str10 name int math2003 math2004 economy2003 economy2004
John 40 13 68 55
Chris 80 64 52 87
Jack 90 55 76 25
Huang 43 60 90 4
Tom 70 68 96 42
Han 53 10 85 89
Phillip 85 61 36 52
Jin 95 6 65 84

实现代码为:

reshape long math economy, i(id name) j(year)
save mylong, replace
export excel using "mylong.xls",firstrow(variable) replace

窗口输出内容

Data Wide -> Long
Number of Observations 8 -> 16
Number of variables 6 -> 5
j variables(2 vlues) -> year
xij variables: ->
math2003 math2004 -> math
economy2003 economy2004 -> economy

3. 绘图

例子

sysuse auto,clear
twoway(scatter mpg weight if foreign==0)	///
	(scatter mpg weight if foreign==1,msymbol(Sh)) /*曲线选项,点的类型*/ ///
	, ///
	title(标题:行驶里程与车重关系) ///
	subtitle(副标题:国产与进口)	///
	ytitle(纵坐标标题) ///
	xtitle(横坐标标题)	///
	note(数据来源:美国汽车协会)	///
	text(35 3400 "曲线类型")	///
	legend(title(图例) label(1 国产车) label(2 进口车))	///
	scheme(slrcolor)

各类图

scatter rainfall year //点
line rainfall year //线
tw area rainfall year //面
///////////////////////////
net install vgsg2,replace
vguse allstates,clear
tw histogram popk //直方图
tw kdensity popk //核估计图
graph bar popk, over(division) //条形图
graph hbar popk, over(division)  //条形图
graph hbox popk, over(division) //箱型图
graph box popk, over(division) //箱型图
graph pie popk, over(region) //饼图
graph matrix propval100 rent700 popden //矩阵图
graph dot popk, over(division) //点阵图

股价数据图

vguse spjanfeb2001, clear
twoway dropline close tradeday //
tw spike close tradeday //针式图
tw dot close tradeday //点线图
tw connected close tradeday, sort //点连线图
tw area close tradeday, sort //和线图类似,显示线以下的面积
tw bar close tradeday,sort /*对每个X绘出相应Y的条图,而graph bar是针对
分类变量X的*/
twoway rarea high low tradeday, sort //显示最高与最低价,并填充两者之间的面积
tw rline high low tradeday, sort //显示最高与最低价,但不填充其间
tw rconnected high low tradeday, sort //显示最低与最高为两点,并连接起来
tw rscatter high low tradeday, sort //显示最低与最高为两点,不连接
tw rcap high low tradeday, sort //两端用小横线标示
tw rspike high low tradeday, sort //两端用点标示
tw rcapsym high low tradeday, sort
对时间序列数据,可以先设定时期,简化命令
tsset tradeday //X轴为时间,由tsset设定.
twoway tsline close, sort //tsline用于时间序列数据,收盘价
tw tsrline high low, sort //最高价与最低价

3a.STATA命令语句格式

很高级,不会,收录只是为了方便查阅

capture program drop gini
program gini
syntax varlist [if] [in] [,title(string)] //设定我们自己的命令格式
tempvar tinc tp m gini //设定tinc tp m gini 四个变量为临时变量
marksample touse //生成一个0/1 暂元,暂元名为touse
preserve //将当前内存中数据暂封存,直到restore 命令再复原
quietly { //大括号内的命令将在后台执行,前台无显示
	keep if `touse' //根据if 后输入的条件得到一个子数据
	egen `tinc'=sum(`1') //生成总收入,将总收入数据暂存在临时变量’tinc’中
	if "`2'"=="" {
		local 2=1
	} //如果没有人口变量,则默认为该变量为1
	egen `tp'=sum(`2')
	gen `m'=`1'/`2'
	sort `m'
	gen `gini'=1-sum(`2'/`tp'*(2*sum(`1'/`tinc')-`1'/`tinc'))
	}
display as result "`title'基尼系数为:" as error `gini'[_N] //显示基尼系数
restore
end

4. Python+Stata

stata在数据处理与分析方面具有一定的优势,而且软件又小,在配置一般的PC机里运行也较为流畅。

4.1 另外保存do文件,在python中运行外部do文件

import subprocess
import codecs
import os
#使用的stata软件路径
stata_path="/Applications/Stata 16/StataSE.app"
#要运行的代码路径
dofile_path="/Users/juncker/dlog/public/local_file/《应用计量经济学讲稿》配套dofile.do"
#cmd中三个参数分别为:stata软件路径、命令、do文件路径
cmd = [stata_path, "doedit", dofile_path]
subprocess.call(cmd)

4.2 有时会遇到改变do文档内容的情形,因此需要在python中写一个do文档

varstr='price length weight'
code='''clear all
sysuse auto
sum
reg '''
statacode=code+varstr #自己编写的do文件代码,不过当前是字符转格式,下一步是将其写入一个do文件
with codecs.open('dofile_2.do','w',encoding='utf-8') as f:
  f.write(statacode)
  f.close()
cmd = [stata_path, "do", dofile_path]
subprocess.call(cmd)
# 关闭stata
os.system('TASKKILL /F /IM StataMP-64.exe')

4.3 在python和stata中传递数据(最容易想到的一个思路是将要传递的内容保存下来,然后python或stata再读取数据)

# 以stata向python传递数据为例
# 首先生成一个stata数据
sysuse auto,clear
keep price
export delimited price using "statatest.txt", delimiter(tab) novarnames replace
# python读取数据
import codecs
with codecs.open('statatest.txt','r',encoding='utf-8') as f:
  data=f.readlines()
  f.close()
print(data)
import re
# 读取的数据包含空格和换行,通过正则表达式提取数据
datamatch=re.compile('[\d]*')
data2=list()
import re
for s in data:
  s=re.match(datamatch,s).group()
  data2.append(s)
print(data2)

PS:

github上有一个ipystata的包可以通过Jupyter在python中使用stata,或者可以参考这篇文章

5. Stata中的Mata

5.1 Mata 基础语法

在正式介绍 Mata 程序编写之前,我们必须了解 Mata 的基础语法,如注释方式、基础运算符、循环、条件语句等。

5.1.1 注释方式 (Comments)

相较 Stata 的 *,Mata 中的注释方式发生了较大改变。如果不事先了解 Mata 的注释方式,那么在命令语句写作和运行中可能会多次报错。输入 help mata comments,可查看相关 help 文档。

Mata 的语句注释分为以下两类:

  1. /* enclosed comment */
  2. // rest-of-line comment

注意点:(1) 注释语句可以出现在 do-files 和 ado-files 中;但不能够在命令窗口的交互状态下使用 (在命令窗口输入 mata 即可进入 Mata 交互状态)。(2) Stata 中利用 “*” 注释在 Mata 中是不允许的。

故在运行命令时有以下注意点:(1)在 Mata 状态下, 由双斜线引导的注释语句在命令窗口中必须连同双斜线一起删除才能 (在命令窗口) 执行 。但在 Do 文件编辑窗口中编写的语句不必删除注释语句,选中全部语句执行即可。(2)Mata 状态下,在 Do 文件编辑窗口中编写的语句不能单独执行。

为更好掌握语法,建议读者在 Stata 命令窗口中输入 mata 进入 Mata 环境 (可通过 end 退出),再将下文中的命令语句删去由 // 注释的文字后,逐行输入命令窗口以感受运算过程。(当然,也可以整体粘贴入 do-file 中运行。)

另一方面,在结果显示中,Mata 的命令提示符是冒号 (😃,而在Stata中是句号 (.)。

5.1.2 运算符 (Operators)

在本部分,主要介绍 Mata 的运算符中的基础运算 (含元素运算)、逻辑运算、下标运算三大内容。有兴趣的读者可以查看3.2.4 运算符优先级总结。Mata 的运算符充分体现了作为矩阵编程语言的特征。

5.1.2.1 基础运算 (部分)

具体运算符和解释已写入以下代码块中,其中较有特色的是元素运算(element-by-element)。

mata //进入 Mata

// --基本运算--
a1=(1,2) //","逗号为列合并运算符
a2=(1..4) //利用".."生成[1,4]范围内的(整数)行向量
a3=(1 \2 \3 \4) //"\"反斜杠为行合并运算符
a4=(1::4) //利用"::"生成[1,4]范围内的(整数)列向量
a5=(1,2)' //"'"撇号为转置运算符

// --代数运算--
b1 = a1 + a1 //"+" 加法
b2 = a1 - a1 //"-" 减法
b3 = a5 * a1 //"*" 乘法

// --例子:混合运算--
c1 = (1, 2, 3 \ 4, 5, 6 \ 7, 8, 9) //生成3×3矩阵
c2 = ((1..3)\(4..6)\(7..9)) //生成的c2矩阵与c1矩阵相同
c3 = (1 \ 2 \ 3 )' //生成行向量


// --元素运算(element-by-element)--
// -注:Mata中的代数运算,包括用于除法的斜杠(/),都可在前面加一个冒号(:),实现元素运算
r1 = ( 1, 2, 3 )
r2 = ( 1, 2, 3 \ 4, 5, 6 \ 7, 8, 9 )
m1 = r1 :+ r2 //将行向量r1中的元素逐行加入到r2的每一行,最终得到3*3矩阵
m2 = r2 :+ r1 //生成的m2与m1相同
m3 = r1 :/ r2 //将行向量r1中的元素逐行除以r2的每一行,得3*3矩阵
m4 = r2 :/ r1 //将行向量r2中的元素逐行除以r1的每一行,得3*3矩阵
m5 = sqrt(m1) //针对每个元素的开根运算

end //退出 Mata

/* 部分结果展示:
: a2
1 2 3 4
+-----------------+
1 | 1 2 3 4 |
+-----------------+

: b3
[symmetric]
1 2
+---------+
1 | 1 |
2 | 2 4 |
+---------+

: m2
1 2 3
+----------------+
1 | 2 4 6 |
2 | 5 7 9 |
3 | 8 10 12 |
+----------------+

: m3
1 2 3
+-------------------------------------------+
1 | 1 1 1 |
2 | .25 .4 .5 |
3 | .1428571429 .25 .3333333333 |
+-------------------------------------------+
*/
5.1.2.2 逻辑运算符 (Logical Operators)

和 Stata 相同,相等逻辑运算符为 a == ba != b 。该逻辑运算不需要考虑 ab 是否一致,或是否是相同类型。其返回值为 0 或 1。

与相等比较不同,余下的逻辑比较运算符 >>=<<= 只可以在两个对象是相同的类型 (数字或字符) 且维数 (conformable) 相同时才可以比较。

而逻辑运算符 与 (&) 或 (|) 只能够用于实数类型的标量 (real scalar)。

5.1.2.3 下标运算 (Subscripts)

Mata 运用中括号 ([]) 进行下标运算,其可以出现在代数表达式的左端或右端。共有两类:① 列表下表 (list subscripts) 和范围下标 (range subscripts)。

利用下标运算,可用于引用、修改、提取数组中元素。

  • 列表下标

下标运算 x[i,j] 中的 ij 可以是一个向量,如:x[i,jvec]jvec=(4,6,8)ij 也可以缺失 (或用 . ) ,用于指代该行或该列中的所有元素,如:x[i,.]x[i,]提取第 i 行的所有元素;x[.,.]x[,]提取整个矩阵中的元素。

为了避免输入每个连续数字,可以用范围运算符 (前文提到的..:: ) 来进行下标运算,如 x[(1..4),.]x[(1::4),.],都指代了矩阵 x 的前四行。同时范围运算也可以是降序的,如 x[(4::1),.]

  • 范围下标

范围下标运算方式为 [| |]。该表达可以用于指代矩阵中的单个元素,但更加重要的是使用 x[| i, j \m, n |],该命令可以生成一个子矩阵,从 x[i, j] 开始至 x[m, n] 结束。形如 x[| 1, 1 \4, .|]x[| 4, 4 \., .|] 也可以正常运行,前者代表了子矩阵至最后一列,后者跳过了 x 矩阵的前三行和前三列。

Tip:当可以同时使用范围下标运算 [| |] 和列表下标运算 [i,j] 时,使用范围下标运算效率更高 ( 无论是矩阵提取还是用时方面 )。

5.1.2.4 运算符优先级总结

参考 Gould(2018, p.86),下标总结了 Mata 中的运算符及其优先级。利用优先级可以简化代码,例如,a>2+3a>(2+3)的实现效果相同 (算术运算优先于逻辑运算)。

运算符优先级汇总 (从高到低)
下标运算 []
递增 & 递减运算 –, ++
结构 & 类元素引用运算 ->, .
指针运算 *, &
算术运算 ', ^, - (负号), /, #, *, -, +
逻辑运算 !, !=, >, <, >=, <=, ==, &, |
行填充
列合并 ,
列填充 ::
行合并 \
三元条件运算 ? :
转为空白 (void)
赋值 =

注:由冒号 : 代表的元素运算优先级仅低于相应的非冒号运算,如 :== 在逻辑运算 == 之后,:* 在代数运算 * 之后。

5.1.3 循环语句 (Loop)

Stata 中的循环有:foreachforvalueswhile,Mata 中的循环也有三类:forwhiledo...while,但是语法多有不同。

forwhile 在循环开始时检查循环的运行条件,这意味着循环可能根本不会执行,可以用于优雅地处理极端情况。而 do...while 在循环结束时检查运行条件,用于需要至少循环一次的情况。

Tip:Mata 作为矩阵语言,在可以使用矩阵运算的时候就应当避免使用明确的循环语句。

5.1.3.1 for

Mata 中的 for 与 C 语言中的循环语句语法类似。

  • 语法
//单行命令
for (exp1; exp2; exp3) statement
//多行命令需要放入大括号中
for (exp1; exp2; exp3) {
statements
}
/*注意点:
- exp1、exp3可以为空,但exp2不可为空
- exp3具体表达中可使用递增(++)或递减(--)运算符,如i++,++i
*/
  • 例子:求1~100见的整数和及平方和
mata //进入mata
v=(1..100)
sum1 = sum2 = 0 //初始化
for (i=1; i<=length(v); i++) {
sum1 = sum1 + v[i]
sum2 = sum2 + v[i]^2
}
(sum1,sum2) //展示结果
end //退出mata

/*输出结果:
: (sum1,sum2)
1 2
+-------------------+
1 | 5050 338350 |
+-------------------+
*/
5.1.3.2 while
  • 语法
//单行命令
while (exp) statement
//多行命令需要放入大括号中
while (exp) {
statements
}
//注意exp必须是与实数标量相比较
  • 例子:求 ,要求精度

Tip:while 通常被用于迭代求解近似值。

mata //进入mata
x=2 //初始化为2
while (abs(x^2-7) > 1e-8){
x = x - (x^2-7)/(2*x) //2*x为f(x)=x^2的求导
}
x //展示结果
end //退出mata

/*输出结果:
: x
2.645751311
*/
5.1.3.3 do…while

do...while 的语法如下:

//单行命令
do stmt while(exp)
//多行命令需要放入大括号中
do {
stmts
} while(exp)
//注意exp必须是与实数标量相比较

5.1.4 条件语句 (Conditional)

与 Stata 类似,在 Mata 中可以使用 if...else 来进行条件判断;不同的是,Mata 中有特殊的三元条件运算符 a ? b : c

5.1.5 if…else

if...else 语法结构如下:

if (exp) statement
//或者
if (exp) statement1
else statement2
//或者
if (exp1) {
statement1
}
else {
statement2
}

if (exp1) {
statements1
}
else if (exp2) {
statements2
}
else {
statements3
}
//注意:exp, exp1, exp2...必须是与实数标量相比较

5.1.6 a ? b : c 条件运算符

  • 语法
a ? b : c
//其中,a必须与实数标量相比较,而b,c的形式不受限制
  • 结果输出

如果 a 为真 (a不为0),则条件运算符返回 b,否则返回 c。

  • 举个例子
mata //进入mata
k = 2
n = 10
dof = ( k==0 ? n-1 : n-k ) //k=0则返回n-1,否则返回n-k
dof
end //退出mata
/*输出结果:
: dof
8
*/

5.2 使用单行命令调用 Mata

5.2.1 实现逻辑及方法

Stata 命令窗口、do-file 或 ado-file 中输入单行命令 mata:一个或多个 Mata 命令,使用分号分割,即可实现 Mata 环境的调用。且我们在 Mata 环境中生成的变量会一直保留,直至输入mata: mata clear

在上文中,我们提到 Mata 的一大优势是灵活的交互以实现 Stata 与 Mata 的互补, mata:语句 的方式就是极佳的实现方式。

但是该交互的前提是两者工作空间内的变量与结果的相互调用或修改,因此,我们不可避免需要用到 st_interface 这类函数。

基于 st_interface 类型的函数,Mata 可以获取 Stata 中的所有对象 (数据、宏、标量和矩阵),并实现 Stata 和 Mata 计算结果的无缝交互。

5.2.2 例子:利用 Mata 提取回归后的 t 值

注:以下例子来源于 Baum(2016) Chapter 13.4

5.2.2.1 问题阐述及分析

在使用 reg 命令后,回归结果的会自动保存在 e() 矩阵中,但 统计量未被保存,那么如何才能计算出 统计量呢?

所幸,e() 中保留了估计系数- e(b) 和估计量的方差-协方差矩阵 e(V) ,从而可以通过 来实现 统计量的计算。

5.2.2.2 Mata 实现
  • 思路如下
  1. 完成回归,获得 e(b)e(B) 矩阵,供 统计量的计算
  2. 通过 st_matrix 函数调用 e(b)e(B) 矩阵,并在 Mata 环境中完成 统计量计算
  3. 完成相关细节调整
  • 代码如下

(命令窗口运行以下语句需删去 //及其注释语句)

*----1.回归----
sysuse auto, clear //调动auto.dta数据集
reg price displacement weight foreign

*----2.单行调用Mata并计算t统计量---
mata: st_matrix("bst",st_matrix("e(b)") :/ sqrt(diagonal(st_matrix("e(V)"))'))
/*该行代码具体解释如下:
st_matrix()的使用可利用 help mata st_matrix 进行查看
bst为逗号后矩阵命名。st_matrix(name, X)将Stata中的名为name的矩阵新建/替换为X中的内容
st_matrix("e(b)")调用系数矩阵
diagonal(st_matrix("e(V)"))'代表提取协方差矩阵后取对角线元素,并转置
利用元素运算符:/完成对应估计量的t统计量运算
*/

*----3.处理生成的bst矩阵的行列名细节----
matrix rownames bst = tstat //行命名
matrix colnames bst = `: colnames e(b)' //列命名
matrix list bst, format(%9.3f) //输出结果

/*矩阵输出结果如下:
. matrix list bst, format(%9.3f)
bst[1,4]
displacement weight foreign _cons
tstat 1.671 3.275 5.745 -2.826
*/

由上述例子可知,通过在 Mata 环境中调用 Stata 中元素,借助 Mata 矩阵运算的优势,轻松实现 统计量的实现,从而实现双方的互补。

5.2.3 Stata 实现

虽然 Mata 可以一键输出,Stata 中处理就一定复杂吗?参考 st: Re: p>t value extraction 给出的答案,代码如下:

sysuse auto, clear //调用auto.dta数据集
reg price displacement weight foreign
matrix a = vecdiag(e(V)) //保存e(V)对角线元素,组成行向量
matrix b = (e(b)\a)' //合并矩阵e(b),a至矩阵b,并转置
svmat b //将矩阵b转化为变量
rename b1 beta //将b1变量(对应b矩阵的第一列)重命名为beta
gen se = sqrt(b2) //对b2变量开根,相当于求出se
gen t = beta/se //得到t统计量
list t in 1/4 //列出所有t统计量的值(因为是变量,所以余下的全部缺失)

/*
. mat list b
b[4,2]
y1 r1
displacement 10.253866 37.671085
weight 2.3286255 .50552151
foreign 3899.6304 460717.13
_cons -4048.3431 2052742.2

. list t in 1/4
+------------+
| t |
|------------|
1. | 1.6706426 |
2. | 3.2751395 |
3. | 5.7452147 |
4. | -2.8255962 |
+------------+
*/

通过对比可知,在回归后生成 统计量,Stata 代码需要 6 行,而使用 Mata 仅需一行。主要原因在于 Stata 中的矩阵无法对其中元素进行逐一的开根号运算,于是无法取出标准误,只能先转化为变量后开根。

以上只是一个小例子,Mata 作为专业矩阵编程语言,可以想象它会为我们的科研带来极大的便利。

Tip:以上的方法都是基于回归后生成的 e() 后计算 统计量 ,实际上使用回归保留的 r(table) 矩阵会更加方便 (目前为止没有找到更简便的方法)。语句如下,有兴趣的读者可尝试。

matrix a=r(table)
matrix b=a[3,1..4]
mat list b

6. 随机模拟

clear
set obs 10
gen x1 = uniform()
gen x2 = uniform()
set seed 1234
gen y1 = uniform()
set seed 1234
gen y2 = uniform()
gen y3 = uniform()
set seed 5634
gen z1 = uniform()
set seed 1234
gen z2 = uniform()
list

6.1 简单重复实验

大部分的人认为连续正面或反面不太容易发生。但模拟结果【连续三次正面】足以修正我们直觉错误。

capture program drop seq3
prog seq3,rclass //rclass 选项表示计算结果将由return 返回到r()
	version 17
	drop _all //清空所有数据,不能用clear
	set obs 10 //将生成10 个观察值
	tempvar x y z //设定x,y,z 为临时变量
	gen `x'=int(10*uniform()) //产生10 个随机变量,可能为0,1,…,9
	gen `y'=(mod(`x',2)==0) //如果生成的随机变量为奇数,则y=0;为偶数,y=1
	gen `z'=0 //生成Z=0
	forvalues i=3/10 {
		replace `z'=1 if `y'==`y'[_n-1] & `y'==`y'[_n-2] in `i' //连续三个变量相等时z=1
	}
	sum `z'
	return scalar max=r(max) //z 取1 表示高兴的事发生(三连续),否则失败
end
simulate max=r(max),reps(10000) nodots:seq3 //重复1 万次,取平均结果
sum

6.2 复杂模拟

任务:一对夫妇计划生孩子生到有女儿才停,或者生了三个就停,他们拥有女儿的概率
是多大?

第一步:概率模型
每一个孩子是女孩的概率是0.49,且各个孩子的性别是互相独立的。
第二步:分配数字
00,01,02,。。。,49=女孩
49,50,51,。。。,99=男孩
第三步:模拟
从随机数表中生成一对一对的数字,直到有了女儿,或已有3个孩子。
重复100次。

capture program drop girl
program girl, rclass
	drop _all
	set obs 3
	gen x = int(100*uniform())
	gen y=(x<49) //生女孩y=1,生男孩,y=0
	sum y
	return scalar max=r(max) //若至少有一个女孩,则max 取1,若三个全为男孩,取0
end
simulate max=r(max),reps(10000) nodots:girl
sum

7. 微观计量经济学实操

参考这篇文章《微观计量经济学》

8. mac stata同时打开两个dta文件

打开【终端.app】:在聚焦搜索里直接搜“终端”或者“terminal”【也可以用iTerm这个软件】,就行

在【终端.app】里输入下面代码:

open -n [stata的安装路径]

怎么确定stata的安装路径?

打开 Finder ,应用程序,看自己的stata安装路径就行。

不过值得注意的是,Mac不太支持路径中包括空格,如果有空格的话,代码会报错。