本章的内容涉及到Stata中的流程控制语句,包括循环语句和条件语句。循环语句有三种命令:forvalues
,foreach
和while
三种。条件语句是 if
/else if
/else
命令。开始学习循环语句的时候需要避免的问题是写出无限循环(死循环)。 在中我们将介绍一部分关于宏(Macros)和标量Scalar的知识,它们是构成流程语句控制的必要工具。
宏 Macros: local/global
local和macro的基本语法
Stata中的宏是类似C语言中宏的概念,我们可以将一些长的、复杂的内容(如数值、字符、表达式)存放于宏中,再后续程序中只需要调用宏就行,而不用把内容写出来,系统会自动把宏替换成其对应的内容来执行程序。注意宏不是变量。
宏Macro可以分为两种:局部宏local和全局宏Macro。二者的区别是作用范围,局部宏在一段程序执行完毕之后即消失,但全局宏可以在代码段执行结束后仍然驻留,可以继续调用。(严格来说,全局宏和局部宏作用范围的区别是在一个函数内部和在整个代码运行过程中,但是我们暂未介绍Stata中如何自定义函数,所以可以按照目前这种不完全正确的理解来记忆,或者至少到目前为止,你可以认为局部宏和全局宏只是在调用方式上存在区别)
看下面这个例子
// local 的用法
sysuse auto, clear
list price length weight in 1/5
local v3 "price length weight" // 将 三个变量名 这组 字符付给local v3
list `v3' in 1/5 // 当调用 local中的内容时需要用一对特殊引号 `',其中左引号是键盘上数字1左边的按键。
local cmd "list"
`cmd' `v3' in 1/5
local make_val1 = price[1] //还可以将变量的某一个取值存放到local中
disp `make_val1'
// global 的用法
sysuse auto, clear
list price length weight in 1/5
global v3 "price length weight"
list $v3 in 1/5 //注意macro的调用方式是用$符号
global cmd "list"
$cmd $v3 in 1/5
. // local 的用法
. sysuse auto, clear
(1978 automobile data)
. list price length weight in 1/5
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
. local v3 "price length weight" // 将 三个变量名 这组 字符付给local v3
. list `v3' in 1/5 // 当调用 local中的内容时需要用一对特殊引号 `',其中左引号
> 是键盘上数字1左边的按键。
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
. local cmd "list"
. `cmd' `v3' in 1/5
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
. local make_val1 = price[1] //还可以将变量的某一个取值存放到local中
. disp `make_val1'
4099
.
.
.
. // global 的用法
. sysuse auto, clear
(1978 automobile data)
. list price length weight in 1/5
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
. global v3 "price length weight"
. list $v3 in 1/5 //注意macro的调用方式是用$符号
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
. global cmd "list"
. $cmd $v3 in 1/5
+-------------------------+
| price length weight |
|-------------------------|
1. | 4,099 186 2,930 |
2. | 4,749 173 3,350 |
3. | 3,799 168 2,640 |
4. | 4,816 196 3,250 |
5. | 7,827 222 4,080 |
+-------------------------+
.
local和macro的用途
1.路径、文件名(或者其中的一部分) 。将复杂的路径名称、文件名等存放在较短的宏中,可以提高代码的可读性,也方便与其他人的交流。
globla PATH "C:/StataClass/
需要指出的是,如果将local作为路径中的一部分,例如C:/StataClass/chap_control/`file'.dta'
,要注意转义符的问题。例如下面的代码希望将auto.dta
保存到目录C:/StataClass/chap_control/
下,名为1.dta的文件。
capture mkdir "C:/StataClass"
capture mkdir "C:/StataClass/chap_control"
local file = 1
sysuse auto, clear
save "C:/StataClass/chap_control/`file'.dta" , replace
. capture mkdir "C:/StataClass"
. capture mkdir "C:/StataClass/chap_control"
. local file = 1
. sysuse auto, clear
(1978 automobile data)
. save "C:/StataClass/chap_control/`file'.dta", replace
file C:/StataClass/chap_control/1.dta saved
.
但你会发现,上面的代码的执行效果是将auto.dta保存成了目录C:/StataClass/
下名为chap_control`file'.dta
的文件。这是因为在Stata中,右斜线 \
除了可以表示windows下路径中的“文件夹”概念之外,右斜线 \
是转意字符,而`
是Stata中的保留符号(用于引用local的内容,前面介绍过)。因此 \`
被作为 `
符号了。为了实现想要的结果,有两种方式:(1)使用左斜线/
而不是右斜线\
来表示路径中的文件夹;(2)在文件夹紧接local符号的位置,使用双右斜线\\
(第一个右斜线其实还是转义字符)。
capture mkdir "C:/StataClass"
capture mkdir "C:/StataClass/chap_control"
local file = 1
sysuse auto, clear
save "C:/StataClass/chap_control/`file'.dta" , replace // 方案1
save "C:/StataClass/chap_control/\`file'.dta" , replace // 方案2
. capture mkdir "C:/StataClass"
. capture mkdir "C:/StataClass/chap_control"
. local file = 1
. sysuse auto, clear
(1978 automobile data)
.
. save "C:/StataClass/chap_control/`file'.dta", replace // 方案1
file C:/StataClass/chap_control/1.dta saved
. save "C:/StataClass/chap_control/\`file'.dta", replace // 方案2
file C:/StataClass/chap_control/`file'.dta saved
.
2.作为循环语句中的判断条件的必要组成部分 。这部分将在下面介绍循环语句的时候详细讲解。
3.变量的取值 例如,下面的代码可以提取出变量的特定取值(例如第1行)
sysuse auto, clear
disp make[1]
local make_val1 = make[1]
di "`make_val1'"
. sysuse auto, clear
(1978 automobile data)
. disp make[1]
AMC Concord
. local make_val1 = make[1]
. di "`make_val1'"
AMC Concord
.
本章末尾的练习题第1题就是利用了这一思路,实现了给CSMAR数据库下载的文件中每一个变量添加label的功能。
4.存储命令的结果 。
Stata的命令会将运算结果放在一些返回结果中,每种命令的返回内容都会因命令而已,主要有以下几类:
对于一般命令(general command)运算的结果,存放在r()
类型的标量(scalar)中;
对于回归相关的命令(例如 regress
的运算结果,存放在e()
类型的标量(scalar)中;
字符串类的运算结果,存放在s()
类型标量中;
关于存储结果的返回(return),将在高阶教程(本教材计划中的第12章《编写程序》中介绍)。大家只需要了解如何使用命令的返回结果即可。 每一条命令,我们可以在命令执行完成后,使用return list
命令查看该指令执行(成功)后,所有返回的结果与相应的数值。对于这些返回结果的含义,我们可以通过 help command
打开对应的帮助手册,在帮助页面的最下方,会有一部分内容的小标题是stored results
。以tabulate oneway
命令为例,可以看到,该命令共返回了两个结果 r(N)
和r(r)
,我们可以使用display
命令查看这些返回结果的取值,也可以将这些结果赋值给local/macro/scalar进行保存,方便后续调用。
sysuse auto, clear
tab rep78
return list
local value_number = r (r )
local obs = r (N )
di "The observation (non-missing) is: `value_number'"
di "The nubmer of unique values of variable rep78 is: `obs'"
. sysuse auto, clear
(1978 automobile data)
. tab rep78
Repair |
record 1978 | Freq. Percent Cum.
------------+-----------------------------------
1 | 2 2.90 2.90
2 | 8 11.59 14.49
3 | 30 43.48 57.97
4 | 18 26.09 84.06
5 | 11 15.94 100.00
------------+-----------------------------------
Total | 69 100.00
. return list
scalars:
r(N) = 69
r(r) = 5
. local value_number = r(r)
. local obs = r(N)
. di "The observation (non-missing) is: `value_number'"
The observation (non-missing) is: 5
. di "The nubmer of unique values of variable rep78 is: `obs'"
The nubmer of unique values of variable rep78 is: 69
.
5.扩展函数
此外,local/macro还可以有一些更复杂的功能,例如可以获取变量的类型、获取变量的显示格式、获取变量的标签、获取特定路径下所有文件的列表、文件夹的列表等。 可以通过help local
在viewer窗口中,点击macro_fcn
查看。这些复杂的功能并不在课程要求的范围内,但是掌握它们能够让你实现一些非常方便和强大的功能。在循环语句的应用中,我们介绍了利用local的dir函数获取某一路径下文件名的方法。
循环语句
Stata中支持的循环语句有三种:while循环、forvalues循环和foreach循环,接下来我们分别介绍。
while循环
while循环的语法结构是
while exp {
Stata command
}
注意,左花括号必须要和while写在同一行。
其中exp 代表一个条件表达式,当满足exp 或者exp 的结果是True时,就执行while循环内部的代码,直到exp 的结果变为False的时候,循环结束。当然,exp 的结果肯定是在不断变化的,通常是循环内部的代码包含该表exp 取值的命令,这样才能循环执行一段时间后最终退出循环。下面一段代码的功能是打印1到10的整数。
local i = 1
while `i' <= 10{
disp "`i'"
local i = `i' +1
}
. local i = 1
. while `i' <= 10{
2. disp "`i'"
3. local i = `i'+1
4. }
1
2
3
4
5
6
7
8
9
10
.
这里需要注意的是,当调用一个local内存放的内容时,需要用`’这对特殊符号括起来。左半边是键盘上数字1左侧按键;右半边是单引号。
下面的代码给出了打印1~20以内所有奇数的代码:
local i = 1
while `i' <= 20{
disp `i'
local i = `i' +2
}
. local i = 1
. while `i' <= 20{
2. disp `i'
3. local i = `i'+2
4. }
1
3
5
7
9
11
13
15
17
19
.
forvalues循环
forvalues循环是循环语句的关键词是forvalues,它的语法结构如下:
forvalues lname = range{
commands referring to `lname'
}
注意左花括号必须和forvalues写在同一行。
这里lname 是指一个local的name,即局部宏的名称。lname 的取值范围由range 来决定。合法(指语法上符合规定)数字范围包括:
#1(#d)#2
meaning #1 to #2 in steps of #d (#代表数字,#d代表整数数字)
#1/#2
meing #1 to #2 in steps of 1
#1 #t to #2
meaning #1 to #2 in steps of #t - #1
#1 #t : #2
meaning #1 to #2 in steps of #t - #1
我们可以用forvalues循环重写 6.2节中打印1到10的整数和打印1到20内基数的例子。
// 打印1到10的整数
forvalues i = 1/10{
disp "`i'"
}
// 打印1到20内的奇数
forvalues i = 1(2)20{
disp "`i'"
}
. // 打印1到10的整数
. forvalues i = 1/10{
2. disp "`i'"
3. }
1
2
3
4
5
6
7
8
9
10
. // 打印1到20内的奇数
. forvalues i = 1(2)20{
2. disp "`i'"
3. }
1
3
5
7
9
11
13
15
17
19
.
forvalues中的逻辑判断条件是通过一个local的数字取值范围实现的,当local的取值在这个数字范围内时,执行循环体内的代码,如果local的取值超出了这个范围,循环结束。这上面的两个例子中,i的取值范围分别是1/10和1(2)20,前者代表1到10步长值为1的递增序列,后者代表1到20步长为2的递增序列。一些数字序列number list的表示方法总结如下:
2
just one number
1 2 3
three numbers
3 2 1
three numbers in reversed order
.5 1 1.5
three different numbers
1 3 -2.17 5.12
four numbers in jumbled order
1/3
three numbers: 1,2,3
1(1)3
same as 1/3
3(-1)1
three numbers in reversed order: 3,2,1
foreach循环
foreach循环和forvalues循环类似,只是不再限定范围是数值序列,而是任意内容的序列均可。foreach循环的语法结构是
foreach lname {in |of listtype} list {
command reffering to `lname'
}
注意,左花括号必须和foreach写在同一行。
foreah中合法的写法包括:
foreach lname in anylist {
foreach lname of local lmname {
foreach lname of global gmname {
foreach lname of varlist varlist {
foreach lname of newlist newvarlist {
foreach lname of numlist numlist {
最后一种写法是和forvalues等价的。 第2中写法是在循环中遍历所有局部宏lmname 的内容,内容以空格隔开。第3中写法是遍历全局宏gmname 的内容,内容以空格隔开。第4中写法是遍历变量列表varlist 中的所有变量。第5中写法是和生成新变量有关。
foreach name in "张三" "李四" "王五" {
di "`name'" //注意不能写成 di `name'
}
local l_name "张三 李四 王五"
foreach name of local l_name {
di "`name'"
}
global g_name "张三 李四 王五"
foreach name of global g_name {
di "$name"
}
sysuse auto, clear
foreach var of varlist mpg price length turn{
des `var'
tostring `var' , generate (`var' _s)
}
des *_s
clear
set obs 10
local i = 0
foreach var of newlist x1-x10{
local i = `i' + 1
gen `var' = _n +`i'
}
list
foreach i of numlist 1(2)10{
di `i'
}
. foreach name in "张三" "李四" "王五"{
2. di "`name'" //注意不能写成 di `name'
3. }
张三
李四
王五
.
. local l_name "张三 李四 王五"
. foreach name of local l_name {
2. di "`name'"
3. }
张三
李四
王五
.
. global g_name "张三 李四 王五"
. foreach name of global g_name {
2. di "$name"
3. }
.
. sysuse auto, clear
(1978 automobile data)
. foreach var of varlist mpg price length turn{
2. des `var'
3. tostring `var', generate(`var'_s)
4. }
Variable Storage Display Value
name type format label Variable label
-------------------------------------------------------------------------------
mpg int %8.0g Mileage (mpg)
mpg_s generated as str2
Variable Storage Display Value
name type format label Variable label
-------------------------------------------------------------------------------
price int %8.0gc Price
price_s generated as str5
Variable Storage Display Value
name type format label Variable label
-------------------------------------------------------------------------------
length int %8.0g Length (in.)
length_s generated as str3
Variable Storage Display Value
name type format label Variable label
-------------------------------------------------------------------------------
turn int %8.0g Turn circle (ft.)
turn_s generated as str2
. des *_s
Variable Storage Display Value
name type format label Variable label
-------------------------------------------------------------------------------
price_s str5 %9s Price
mpg_s str2 %9s Mileage (mpg)
length_s str3 %9s Length (in.)
turn_s str2 %9s Turn circle (ft.)
.
. clear
. set obs 10
Number of observations (_N) was 0, now 10.
. local i = 0
. foreach var of newlist x1-x10{
2. local i = `i' + 1
3. gen `var' = _n+`i'
4. }
. list
+--------------------------------------------------+
| x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 |
|--------------------------------------------------|
1. | 2 3 4 5 6 7 8 9 10 11 |
2. | 3 4 5 6 7 8 9 10 11 12 |
3. | 4 5 6 7 8 9 10 11 12 13 |
4. | 5 6 7 8 9 10 11 12 13 14 |
5. | 6 7 8 9 10 11 12 13 14 15 |
|--------------------------------------------------|
6. | 7 8 9 10 11 12 13 14 15 16 |
7. | 8 9 10 11 12 13 14 15 16 17 |
8. | 9 10 11 12 13 14 15 16 17 18 |
9. | 10 11 12 13 14 15 16 17 18 19 |
10. | 11 12 13 14 15 16 17 18 19 20 |
+--------------------------------------------------+
.
. foreach i of numlist 1(2)10{
2. di `i'
3. }
1
3
5
7
9
.
多层循环
多层循环,又称嵌套循环,是在循环之内再叠加循环,可以实现相对复杂功能。例如下面的代码可以生成一个数据,包含5个变量、10行观测值,第i
个变量的第j
个观测值是i+j
。
clear
set obs 10
forval i = 1/5{
gen x`i' = 0
forval j = 1/10{
replace x`i' = `i' +`j' if _n == `j'
}
}
list
. clear
. set obs 10
Number of observations (_N) was 0, now 10.
. forval i = 1/5{
2. gen x`i'= 0
3. forval j = 1/10{
4. replace x`i' = `i'+`j' if _n == `j'
5. }
6. }
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
(1 real change made)
. list
+------------------------+
| x1 x2 x3 x4 x5 |
|------------------------|
1. | 2 3 4 5 6 |
2. | 3 4 5 6 7 |
3. | 4 5 6 7 8 |
4. | 5 6 7 8 9 |
5. | 6 7 8 9 10 |
|------------------------|
6. | 7 8 9 10 11 |
7. | 8 9 10 11 12 |
8. | 9 10 11 12 13 |
9. | 10 11 12 13 14 |
10. | 11 12 13 14 15 |
+------------------------+
.
条件语句
条件语句我们在介绍命令的语法结构时就涉及过。例如,我们通过下面的代码可以在数据auto.dta中新增一个价格变量p1
,且p1
的取值会因为国产车和进口车两种类型存在差异——如果是国产车,则价格降 100 元,如果是进口车,则价格提升 200 元。
sysuse auto, clear
gen p1 = price-100 if foreign == 0
replace p1 = price+100 if foreign == 1
// 这个写法与p1的计算等价
gen p2 = cond (foreign==0,(price-100),(price+100))
list p * price in 1/5
. sysuse auto, clear
(1978 automobile data)
. gen p1 = price-100 if foreign == 0
(22 missing values generated)
. replace p1 = price+100 if foreign == 1
(22 real changes made)
. // 这个写法与p1的计算等价
. gen p2 = cond(foreign==0,(price-100),(price+100))
. list p* price in 1/5
+-----------------------------+
| price p1 p2 price |
|-----------------------------|
1. | 4,099 3999 3999 4,099 |
2. | 4,749 4649 4649 4,749 |
3. | 3,799 3699 3699 3,799 |
4. | 4,816 4716 4716 4,816 |
5. | 7,827 7727 7727 7,827 |
+-----------------------------+
.
除了作为命令的一部分,条件语句还具有流程控制的功能。语法结构如下
if exp1 {
Stata command
}
else if exp2{
Stata command
}
else {
Stata comamnd
}
这里exp1
, exp2
都代表逻辑语句,可以是简单逻辑语句如foreign>100
,也可以是符合逻辑语句,如var1>100|var<50
条件语句也可以和循环来连用,实现一些更复杂的功能。例如,下面的代码可以实现输出1到10中的偶数和奇数。
forval i = 1/10{
if mod (`i' ,2) == 0{
disp "`i' 是个偶数"
}
else if mod (`i' ,2) == 1{
disp "`i' 是个奇数"
}
}
. forval i = 1/10{
2. if mod(`i',2) == 0{
3. disp "`i' 是个偶数"
4. }
5. else if mod(`i',2) == 1{
6. disp "`i' 是个奇数"
7. }
8. }
1 是个奇数
2 是个偶数
3 是个奇数
4 是个偶数
5 是个奇数
6 是个偶数
7 是个奇数
8 是个偶数
9 是个奇数
10 是个偶数
.
如果设定合理,循环语句可以自动结束。例如foreach i = 1/10
这样的一个循环中,local i
的取值会从1一直累加,直到10后,循环结束。但我们也可以通过continue
和break
命令与条件语句连用,实现特定的条件下退出循环和继续循环的功能。例如下面的例子可以计算得到6-500之间能够同时被2、3、5整除的最小的数字。
forval i = 6/500{
if mod (`i' ,2) == 0 & mod (`i' ,3) == 0 & mod (`i' ,5) == 0{
disp "the LEAST common multiple of 2,3 ,and 5 is `i'
continue,break
}
}
. forval i = 6/500{
2. if mod(`i',2) == 0 & mod(`i',3) == 0 & mod(`i',5) == 0{
3. disp "the LEAST common multiple of 2,3 ,and 5 is `i'
4. continue,break
5. }
6. }
the LEAST common multiple of 2,3 ,and 5 is 30
.
continue的功能是忽略当前循环内continue
之后的所有代码,即调出循环。continue, break
是不再执行后续的取值的循环。例如在上面的例子里,再执行到`i’==30之后,就不再执行31-500的循环。
一个综合应用
下面的代码演示了如何将实现了从数据文件stock_trade_data202101.dta
按照股票代码进行拆分以及再将数据拼接在一起的方法。 我们在第二章使用过的个股交易数据,它是从CCER数据库下载得到,涵盖了全部A股上市公司在2021年1月的日度交易数据。你可以从企业微信群内获取该数据文件。为了简化处理,我们仅使用该数据中的股票代码
、交易日期
和收盘价
指标。
// 假定数据存放在C:/StataClass/chap_file下
global data_dir "C:/StataClass/chap_file"
global process_dir "C:/StataClass/chap_control"
use "${data_dir}/stock_trade_data202101.dta" , clear
keep 股票代码 日期 收盘价
compress
destring _all , replace
save "${process_dir}/data.dta" , replace
. // 假定数据存放在C:/StataClass/chap_file下
. global data_dir "C:/StataClass/chap_file"
. global process_dir "C:/StataClass/chap_control"
.
. use "${data_dir}/stock_trade_data202101.dta", clear
. keep 股票代码 日期 收盘价
. compress
(0 bytes saved)
. destring _all, replace
日期: all characters numeric; replaced as long
股票代码: all characters numeric; replaced as long
收盘价: all characters numeric; replaced as double
. save "${process_dir}/data.dta", replace
file C:/StataClass/chap_control/data.dta saved
.
下面的代码,可以实现按照股票代码从该数据中提取交易数据,每支股票的交易数据单独存放,文件名是各自的股票代码。 这里使用了一个levelsof
的命令,levelsof 股票代码, local(stkcd_list)
会将所有股票代码的取值存放到名为stock_list
的宏中。我们可以使用foreach
循环从这个local中把每一个股票代码逐次取出。
global process_dir "C:/StataClass/chap_control"
capture mkdir "${process_dir}/split"
use "${process_dir}/data.dta" , clear
levelsof 股票代码, local (stkcd_list)
di "`stkcd_list'"
foreach i_stkcd of local stkcd_list{
use "${process_dir}/data.dta" , clear
di `" 保存股票代码为`i_stkcd' 的股票:"'
keep if 股票代码 == `i_stkcd'
save " ${process_dir} /split //`i_stkcd'.dta", replace
}
下面的代码,可以通过append命令将原有数据复原。
global process_dir "C:/StataClass/chap_control"
clear
local file_list: dir "${process_dir}/split" files "*.dta"
foreach i_file of local file_list{
di "i_file is: `i_file'"
local i_stkcd = subinstr ("`i_file'" ,".dta" ,"" ,.)
di "股票代码 is: `i_stkcd'"
append using "${process_dir}/split//`i_file'"
}
compress
save "${process_dir}/data_split_append.dta" , replace
可以对比一下data.dta
与data_split_append.dta
,数据是一样的(但是数据的排序不一样,data.dta
是先按照日期、再按照股票代码排序,data_split_append.dta
是先按照股票代码、再按照日期排序,思考一下这是为什么?)
练习
1.将CSMAR下载的数据文件公司基本情况表 CG_Co.xlsx 文件读入Stata,要求:将第一行作为变量名,第二行和第三行的内容合并作为变量的标签(label)。 (提示:给变量添加label的语法是 label variable varname label
,例如 label variable stkcd "股票代码"
,你可以通过help label
查看帮助手册;在本章7.1.2节中我们介绍了如何使用local提取变量第1行的取值的方法)
2.将1到10的数字输出,其中1到9补0,即01,02,…,10。
3.在7.4节中,我们使用循环实现了将股票交易数据的拆分与合并——按照股票代码提取每一支股票的数据并单独存放,然后用append命令进行(几乎一模一样)的还原。
我们还可以利用循环语句实现长宽转换的功能。例如,我们首先使用reshape
命令将数据做如下转化:
global process_dir "C:/StataClass/chap_control"
use "${process_dir}/data.dta" , clear
reshape wide 收盘价,i(股票代码) j(日期)
可以看到,数据从3个变量变成了21个变量,原因是我们将每一天的收盘价格单独作为一个变量。 请借鉴7.4节中思路和方法,利用循环语句和merge
命令实现上面的转换过程。