查看原文
其他

Stata:generate 函数、if 表达式与常用 egen 函数汇总

RStata RStata 2023-10-24

欢迎各位培训班会员参加明晚的第 4 次直播课:「函数、宏、标量和矩阵(一)」。

因为上次课程的内容没有讲完,明晚我们会继续讲解 generate 函数、if 表达式和常用 egen 函数汇总的内容。

该课程是「Stata 编程导论的第 3 课时」,课程主页(点击文末的阅读原文即可跳转):

https://rstata.duanshu.com/#/brief/course/57571646805e4786b622867cfd5ad1d9


本次课及下面的几讲内容将集中于 Do 文档的编程。这节课我们将讲解 Do 文档编程中的一些基础概念:函数、宏、标量和矩阵。

一些编程的细节

本节我们将使用 census2c 数据集:

clear all

*- 一些编程的细节
use census2c, clear
list, sep(0)

*>     +---------------------------------------------------------------------+
*>     | state           region        pop    popurb   medage    marr   divr |
*>     |---------------------------------------------------------------------|
*>  1. | Connecticut     NE         3107.6    2449.8    32.00    26.0   13.5 |
*>  2. | Illinois        N Cntrl   11426.5    9518.0    29.90   109.8   51.0 |
*>  3. | Indiana         N Cntrl    5490.2    3525.3    29.20    57.9   40.0 |
*>  4. | Iowa            N Cntrl    2913.8    1708.2    30.00    27.5   11.9 |
*>  5. | Kansas          N Cntrl    2363.7    1575.9    30.10    24.8   13.4 |
*>  6. | Maine           NE         1124.7     534.1    30.40    12.0    6.2 |
*>  7. | Massachusetts   NE         5737.0    4808.3    31.20    46.3   17.9 |
*>  8. | Michigan        N Cntrl    9262.1    6551.6    28.80    86.9   45.0 |
*>  9. | Minnesota       N Cntrl    4076.0    2725.2    29.20    37.6   15.4 |
*> 10. | Missouri        N Cntrl    4916.7    3349.6    30.90    54.6   27.6 |
*> 11. | Nebraska        N Cntrl    1569.8     987.9    29.70    14.2    6.4 |
*> 12. | New Hampshire   NE          920.6     480.3    30.10     9.3    5.3 |
*> 13. | New Jersey      NE         7364.8    6557.4    32.20    55.8   27.8 |
*> 14. | New York        NE        17558.1   14858.1    31.90   144.5   62.0 |
*> 15. | N. Dakota       N Cntrl     652.7     318.3    28.30     6.1    2.1 |
*> 16. | Ohio            N Cntrl   10797.6    7918.3    29.90    99.8   58.8 |
*> 17. | Pennsylvania    NE        11863.9    8220.9    32.10    93.7   34.9 |
*> 18. | Rhode Island    NE          947.2     824.0    31.80     7.5    3.6 |
*> 19. | S. Dakota       N Cntrl     690.8     320.8    28.90     8.8    2.8 |
*> 20. | Vermont         NE          511.5     172.7    29.40     5.2    2.6 |
*> 21. | Wisconsin       N Cntrl    4705.8    3020.7    29.40    41.1   17.5 |
*>     +---------------------------------------------------------------------+

Stata 中的数据集也是表式的,表的每一行我们称为观测值,每一列我们称为变量。从上面的结果中我们可以看到,census2c.dta 数据集一共有 21 个观测值和 7 个变量。

Stata 数据集中的变量名称必须是互不相同的,同时还要遵守下面的规则:

  1. 不能包含空格;
  2. 不能包含运算符,例如 -, +, *, /
  3. 不能包含 ., ?
  4. 不能以数字开头;
  5. 大小写敏感;
  6. 其它暂时没想起来的。

建议不要使用中文变量名,变量名不宜使用 a, b, c 这种缺乏实际含义的字符,可以使用简单的英文或英文缩写。例如 pop 之类的。

变量列表

help varlist

很多 Stata 命令可以处理不止一个变量,也就是可以接受变量列表,例如:

sum pop - divr

*>     Variable |        Obs        Mean    Std. dev.       Min        Max
*> -------------+---------------------------------------------------------
*>          pop |         21    5142.903    4675.152    511.456   17558.07
*>       popurb |         21    3829.776    3851.458    172.735   14858.07
*>       medage |         21    30.25714    1.199821       28.3       32.2
*>         marr |         21    46.16905     39.9059      5.226    144.518
*>         divr |         21    22.17948    19.31113      2.142     61.972

sum pop*

*>     Variable |        Obs        Mean    Std. dev.       Min        Max
*> -------------+---------------------------------------------------------
*>          pop |         21    5142.903    4675.152    511.456   17558.07
*>       popurb |         21    3829.776    3851.458    172.735   14858.07

sum *r

*>     Variable |        Obs        Mean    Std. dev.       Min        Max
*> -------------+---------------------------------------------------------
*>         marr |         21    46.16905     39.9059      5.226    144.518
*>         divr |         21    22.17948    19.31113      2.142     61.972

sum pop popurb

sysuse auto, clear
reg price mpg - for

*>       Source |       SS           df       MS      Number of obs   =        69
*> -------------+----------------------------------   F(10, 58)       =      8.66
*>        Model |   345416162        10  34541616.2   Prob > F        =    0.0000
*>     Residual |   231380797        58  3989324.09   R-squared       =    0.5989
*> -------------+----------------------------------   Adj R-squared   =    0.5297
*>        Total |   576796959        68  8482308.22   Root MSE        =    1997.3
*> 
*> ------------------------------------------------------------------------------
*>        price | Coefficient  Std. err.      t    P>|t|     [95% conf. interval]
*> -------------+----------------------------------------------------------------
*>          mpg |  -21.80518    77.3599    -0.28   0.779    -176.6578    133.0475
*>        rep78 |   184.7935   331.7921     0.56   0.580    -479.3606    848.9476
*>     headroom |  -635.4921   383.0243    -1.66   0.102    -1402.198    131.2142
*>        trunk |   71.49929   95.05012     0.75   0.455    -118.7642    261.7628
*>       weight |   4.521161   1.411926     3.20   0.002     1.694884    7.347438
*>       length |  -76.49101   40.40303    -1.89   0.063    -157.3665     4.38444
*>         turn |  -114.2777   123.5374    -0.93   0.359    -361.5646    133.0092
*> displacement |   11.54012   8.378315     1.38   0.174    -5.230896    28.31115
*>   gear_ratio |  -318.6479    1124.34    -0.28   0.778    -2569.259    1931.964
*>      foreign |   3334.848   957.2253     3.48   0.001     1418.754    5250.943
*>        _cons |   9789.494   6710.193     1.46   0.150    -3642.416     23221.4
*> ------------------------------------------------------------------------------

foreach i of varlist _all{
 di "`i'"
}

foreach i of varlist make price{
 list `i' in 1
}

tostring make price, replace
tostring _all, replace
destring _all, replace

数值列表

help numlist

数值列表的用途也很广泛:

forval i = 1/10{
 di "`i'"
 di `i' + 1
}

forval i = 1(2)10{
 di "`i'"
}

forval i = 10(-2)1{
 di "`i'"
}

forval i = 10 15 to 30{
 di "`i'"
}

foreach i in 1 2 3 4 5{
 di "`i'"
}

sysuse uslifeexp, clear
line le_wm year, yla(0 20(10)80)

if / in

help if
help in

很多 Stata 命令可以使用 if 或者 in 进行观测值筛选:

use census2c, clear
list state pop medage if medage >= 32
reg pop medage if medage >= 30

*>       Source |       SS           df       MS      Number of obs   =        11
*> -------------+----------------------------------   F(1, 9)         =      4.42
*>        Model |  89780675.1         1  89780675.1   Prob > F        =    0.0649
*>     Residual |   182823809         9  20313756.6   R-squared       =    0.3293
*> -------------+----------------------------------   Adj R-squared   =    0.2548
*>        Total |   272604484        10  27260448.4   Root MSE        =    4507.1
*> 
*> ------------------------------------------------------------------------------
*>          pop | Coefficient  Std. err.      t    P>|t|     [95% conf. interval]
*> -------------+----------------------------------------------------------------
*>       medage |   3378.154   1606.879     2.10   0.065    -256.8585    7013.166
*>        _cons |  -99897.76   50080.02    -1.99   0.077    -213186.6    13391.12
*> ------------------------------------------------------------------------------

list state pop in 1/5
reg pop medage in 1/10
keep in 1/10

*- help programming functions
list if inrange(medage, 30, 32)
list if inlist(state, "Connecticut""Illinois")

缺失数据的处理

help missing

Stata 中有 27 中数值型缺失值。

. 是默认的数值缺失值,也被称为系统缺失值,.a, .b, .c, ..., .z 则被称为拓展缺失值。这些缺失值和非缺失值的大小关系是:

list if age > 60 & age < .
list if age >= .
drop if missing(divr)
drop if missing(divr, marr)

字符串型缺失值是 "" 括起来的空值。

一些 Stata 命令可以在运算的时候自动处理缺失值,而处理的通常方式是删除缺失值。

clear 
input x1 x2 x3 x4
1 2 . 4
4 5 .a 4
6 . .b 5
7 18 .c 9
end

egen min = min(x3)  // 忽略了缺失值
egen max = max(x2) // 忽略了缺失值
egen rowmax = rowmax(x1 x2 x3)  // 忽略了缺失值

correlate x1 x2 x4 // 忽略含缺失值的观测值
correlate x1 x2 x4 if !missing(x2)

pwcorr x1 x2 x4 // 利用所有的成对数据
pwcorr x1 x2 x4 if !missing(x2)

数值型变量的缺失值可以使用 mvdecode 或者 mvencode 处理:

mvencode x2, mv(. = 0)
mvencode x3, mv(. = 1 \ .a = 2)
mvdecode x2, mv(18)
mvdecode x2, mv(2 = . \ 5 = .a)

字符型变量转数值型变量

gen id = _n
gen idstr = string(id)
gen idnum = real(idstr)
gen statestr = real(state)
destring _all, replace
tostring _all, replace

encode state, gen(statenum)
decode region, gen(regionstr)

use census2c, clear
gen pop3 = strofreal(pop, "%6.3f")
gen pop4 = string(pop, "%6.3f")
tostring pop, gen(pop5)

clear all
set obs 10
gen date = _n
tostring date, format(%tdCY-N-Dreplace
gen date2 = string(date, "%tdCY-N-D")

还有一个需要注意的是带引号的字符串。我们可以使用绝对引号括起来:

di `""Hello""'
di "Hello"
di "1+2"
di "`=date2[1]'"
di `""`=date2[1]'""'
di "`=1+2'"

generate 函数

use census2c, clear
gen urbanized = popurb / pop
sum urbanized

replace urbanized = 100 * urbanized
sum urbanized

gen newengland = inlist(state, "Connecticut""Maine"///
 "Massachusetts""New Hampshire""Rhode Island""Vermont")
gsort newengland
list state medage pop if newengland, sep(0)

list state medage pop if inrange(pop, 5000, 9999), sep(0)

replace divr = int(divr)
gen divrmod = mod(divr, 2)

gen stateC = substr(state, 1, 1)
keep pop
gen popsum = sum(pop)
egen poptotal = total(pop)

if 表达式和示性变量

示性变量又被称为指示变量、虚拟变量、零一变量、逻辑变量。

use census2c, clear
gen smallpop = 0 
replace smallpop = 1 if pop <= 5000 & !missing(pop)
gen largepop = 0
replace largepop = 1 if pop > 5000 & !missing(pop)
list state pop smallpop largepop, sep(0)

示性变量也可以参与计算,例如:

sysuse auto, clear
gen wt = 10 * (rep78 == 1) + 20 * (rep78 == 2) + 30 * (rep78 == 3)

cond() 函数

use census2c, clear
gen netmarr2x = cond(marr/divr > 2.0, 1, 2)
label def netmarr2xc 1 "marr > 2 divr" 2 "marr <= 2 divr"
label val netmarr2x netmarr2xc
tabstat pop medage, by(netmarr2x)

连续变量与离散变量之间的转换

use census2c, clear
gen medagebrack = recode(medage, 29, 30, 31, 32, 33) // 包括右边不包括左边
tab medagebrack

gen size = irecode(pop, 1000, 4000, 8000, 20000)
label def popsize 0 "<1m" 1 "1-4m" 2 "4-8m" 3 ">8m"
label val size popsize
tabstat pop, stat(mean min max) by(size)

help pctile
use census2c, clear
xtile medagequart = medage, nq(4)
tabstat medage, stat(n mean min max) by(medagequart)

*- 计算分位数并存储起来
use census2c, clear
_pctile medage, nq(4)
ret list

egen 函数

egen 函数太多了,有很多非常好用的,我这里列举一些:

egen 与常见统计量

clear
set obs 10

*- 生成1-10的连续序列
gen A = _n

*- 生成总的观测值数
gen num = _N

*- 得到变量A的均值
egen avg = mean(A)
egen med = median(A)
egen std = sd(A)
egen min = min(A)
egen max = max(A)

egen 参与分组和排序

clear
set obs 10
gen A = _n
gen num = _N
*- 根据奇偶数分组,偶数为0,奇数为1
gen se = mod(A, 2)

*- 根据奇偶数分组,A只参与排序,不参与分组求分组后组列总和
bysort se(A): egen sum = sum(A)
bysort seegen sum0 = sum(A)

*- A既参与分组也参与排序,求分组后的组总和
bysort se A : egen sum1 = sum(A)

*- 根据奇偶数分组,求分组后的组列累计和
bysort se(A): gen sum2 = sum(A)

sort se
list A se sum sum1 sum2

egen 与 seq

两者搭配可以生成有规律的连续序列:

clear
set obs 10
gen a1 = _n

*- 生成 1 - 10
egen a2 = seq()

*- 生成 1 - 10
range a3 1 _N

*- 根据奇偶数分组
gen se = mod(a1, 2)

*- 根据奇偶数分组之后,连续序列中的每个数字重复两次
bysort se(a1): egen b = seq(), block(2)

*- a1 也参与分组
bysort se a1 : egen b1= seq(), block(2)

*- 分组之后,变量 c 的序列从 3 到 1 递减并循环
bysort se(a1): egen c = seq(), from(3) to(1)

*- 分组之后,变量 d 从 1 到 3 循环
bysort se(a1): egen d = seq(), to(3)

egen 与 fill

egen 与 fill()搭配也可以生成一串规律的序列,在某些情况下,fill 与 seq 起到的效果是一样的,不同点在于 seq 的步长只能为 1,而 fill 可以自己设定步长:

clear
set obs 10

*- 按 1、3、5 的规律填充 
egen a = fill(1 3 5)

*- 按 1、2 的规律填充
egen b = fill(1 2)

*- 从 6 开始到 3,步长为 -3
egen c = fill(6(-3)3)

*- 按1、1、2、2的规律填充
egen d = fill(1 1 2 2)

*- 按 1、1、2、1、1、2 的规律填充
egen e = fill(1 1 2 1 1 2)
egen f = fill(-3(3)6 -3(3)6)
egen g = fill(10 20 to 50 10 20 to 50)

fill 不能与 bysort 结合使用!

egen 与 diff

egen 与 diff 搭配时,若 varlist 中的变量值都相同,则给 diff 赋值为 0,否则为 1:

clear
use egenxmpl3, clear
egen differ = diff(inc*)

egen 与 row 函数

clear
use egenxmpl4, clear

*- rowtotal()、rowmean() 和 rowsd()函数会忽略缺失值
egen total = rowtotal(a b c)
egen avg = rowmean(a b c)
egen std = rowsd(a b c)

*- 得到缺失值的个数
egen miss = rowmiss(a b c)

*- 最小值
egen min = rmin(a b c)

*- 得到该行最后一个变量值(缺失值不计入)
egen last = rlast(a b c)

egen 与 pc、pctile

sysuse auto, clear
keep mpg
*- 得到列总和
egen sum = sum(mpg)
*- 得到每个观测值占列总和的比例(小数)
egen per = pc(mpg), prop
*- 百分数
egen per_1 = pc(mpg)
*- 得到 mpg 的 0.25 分位数
egen pct = pctile(mpg), p(25)
*- 中位数
egen pct_1 = pctile(mpg)

egen 与 rank

sysuse auto, clear
keep in 16/30
keep mpg
*- 正序无并列排名
egen rank_u = rank(mpg), unique
*- 正序排名,排名可能会出现0.5
egen rank = rank(mpg)
*- 倒序排名
egen rank_r = rank(-mpg)
*- 指定最小观测值排名为1,若出现相同数字,并列排名
egen rank_t = rank(mpg), track
*- 指定最大观测值排名为1,若出现相同数字,并列排名
egen rank_f = rank(mpg), field

egen 与 anyvalue、anymatch

sysuse auto, clear
keep rep78

*- 若rep78不为3、4、5,则为缺失值
egen a = anyvalue(rep78), v(3/5)

*- 若rep78不为3、4、5,则赋值为0,否则为1
egen b = anymatch(rep78), v(3/5)

egen 与 std

use states1, clear
*- 将age标准化为均值为0,方差为1的变量
egen stdage = std(age)
sum age stdage
*- 两者的相关系数为1
corr age stdage
*- 生成均值为1(不指定均值时默认为0),标准差为2的变量
egen newage1 = std(age), std(2)
*- 均值为2,标准差为4
egen newage2 = std(age), mean(2) std(4)
egen newage3 = std(age), mean(2)
sum age new*

更多 egen 函数我就不再继续讲解了,布置一个作业:

这些命令是外部命令,我已经把安装包放在了附件中,可以使用下面的命令安装:

例如 _gclsort:

net install _gclsort.pkg, from("_gclsort.pkg 文件所在的文件夹路径(这个路径不包含 _gclsort.pkg 的名字)") force replace

例如在我的电脑上(_gclsort.pkg 文件在 /Users/ac/Documents/ssc/_gclsort/ 文件夹中):

net install _gclsort.pkg, from("/Users/ac/Documents/ssc/_gclsort/") force replace

其他的也都类似。

自我学习:

  1. clsort
*- 使用
clear
input ///
varname1   select
  20         0
  40         1
  15         1
  10         1
  55         0
  60         1
end
egen default = clsort(varname1) if select
egen inplace = clsort(varname1) if select, inplace
  1. peers
*- 使用
sysuse auto, clear
keep weight foreign
egen peers = peers(weight), by(foreign)
gsort foreign
replace weight = . in 1
bysort foregen mean = mean(weight)
  1. egenmore & egenmisc
help egenmore
help egenmisc

例如:egen + mlabvpos 改变标签的方向减少遮盖:

use allstates, clear
egen clock = mlabvpos(ownhome propval100)
tw sc ownhome propval100, ///
 mla(stateab) ///
 mlabsize(small) ///
 mlabvpos(clock)
  1. gwtmean
*- 使用
sysuse auto, clear
keep rep78 price
egen wtmean = wtmean(price), weight(rep78)
*- 上面的计算结果和下面的结果是一样的
sum price [w=rep78]
  1. 搜集更多的 egen 拓展函数。

由于时间关系,今天的内容就先到这里了。谢谢~

直播信息

为了让大家更好的理解上面的内容,欢迎各位培训班会员参加明天晚上 9 点的直播课:「函数、宏、标量和矩阵(一)」

  1. 直播地址:腾讯会议(需要报名 RStata 培训班参加)
  2. 讲义材料:需要报名 RStata 培训班,详情可阅读:一起来学习 R 语言和 Stata 啦!学习过程中遇到的问题也可以随时提问!

更多关于 RStata 会员的更多信息可添加微信号 r_stata 咨询:

预定纸质版讲义材料

在之前的课程结尾我把讲义材料整理成了一本讲义材料,感兴趣的小伙伴可以联系微信号 r_stata 李老师预定(Stata 编程导论是 55元/本,255 页彩色胶装):

购买长期会员有赠送纸质书哦!


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存