温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh
作者: Skylar B.Y. Sun
目录
编者按: 本文主要编译自以下两篇文章,特此感谢!
Source:
Halpin, B. (2017). SADI: Sequence analysis tools for Stata. The Stata Journal, 17(3), 546-572. -PDF-
Brzinsky-Fay, C., Kohler, U., & Luniak, M. (2006). Sequence analysis with Stata. The Stata Journal, 6(4), 435-460. -PDF-
生命历程调查 (Life History Analysis) 最近几年在社会学中越来越火热。与传统的只可以抓住特定时点的回归分析相比,生命历程调查最大的优势就是可以捕捉到一个人很长一段岁月中发生的故事。回归分析专注于找出样本的一个平均代表,而生命历程中的聚类分析则更倾向于通过细节找出一个群体中各种不同的小群体,旨在画出一幅包罗万象的丰富画卷。生命历程数据有很多研究方法,当下最火热的一种便是序列分析 (Sequence Analysis)。目前,常用的统计软件 R 和 Stata 都有序列分析相关的命令包,且 Stata 的命令相对更为丰富。因此,这篇就向大家介绍一下如何用 Stata 分析生命历程的数据。
Sequence 这个概念的缘起就是我们常说的 DNA 链条,后来逐渐发展成了社会学中的生命历程 sequence。Sequence 定义为遗传按次序排列的元素 (element),比如说下图中的每个方格位置都是一个元素。每个元素都代表一个特定的状态 (status),比如说工作状态、婚姻状态等。比如说下图中一共有五种状态,分别是 A B C E N。在一条 sequence 中,每个元素的都有其固定的位置。比如说 Position 7 上的元素是 A 。同一个元素连续出现了好几次便组成 元素片段 (episode / spell)。比如说 P6 到 P9 四个位置上的 A 就组成了一个元素片段。片段越长则代表对应的时间越长 (longer duration)。
Source: Cornwell, Benjamin. Social sequence analysis: Methods and applications. Vol. 37. Cambridge University Press, 2015. pp 59.
序列数据 (sequence data) 与截面时间序列数据 (cross-sectional time-series data) 及生存分析数据 (survival data) 有一些相似之处,比如说时间都是这种数据中的一个重要的组成部分。不过,与后两者不同的是,序列数据中的位置 (position) 一般指的是相对时间点,而不是一个绝对时间点。同时,每一条 sequence 都是被当成一个完整的个体去分析,且 sequence 中每一个元素都与这条 sequence 的特点息息相关。与生存分析数据还有一个不同,即序列数据中没有风险比的这个概念。
Stata 目前有两套主要用于 sequence analysis 的命令。请按照如下方式安装。
net from http://teaching.sociology.ul.ie/sadi
net install sadi /*导入最新版本的 sadi 命令*/
ssc install moremata
ssc install sq /*主要用来画 sequence index plot*/
在下面的例子中,我们将使用 McVicar 和 Anyadike-Danes (2002) 年的一套人物状态变换的数据。数据包括了连续72个月的数据点 / 位置 (state1 to state72)。每个位置有六种可能的元素,分别是受雇 (employment)、继续教育 (further education)、高等教育 (higher education)、高中教育 (secondary education)、培训 (training) 及失业 (unemployment)。
use http://teaching.sociology.ul.ie/bhalpin/mvad /*数据导入*/
describe
Contains data from mvad.dta
obs: 712
vars: 86 20 Dec 2020 20:53
size: 244,928
----------------------------------------------------------
storage display value
variable name type format label variable label
----------------------------------------------------------
id float %9.0g
state1 float %9.0g state 1 state
state2 float %9.0g state 2 state
state3 float %9.0g state 3 state
state4 float %9.0g state 4 state
state5 float %9.0g state 5 state
(output omitted)
state72 float %9.0g state 72 state
(output omitted)
livboth float %9.0g
--------------------------------------------------------
Sorted by: id
虽然之后我们也会介绍一种通过数据信息自己生成的转换矩阵,但在不少研究中,很多学者依旧倾向于自定义转换矩阵。
定义转换矩阵的原则主要是基于作者对于不同状态之间差别的理解。比如说,同一个状态之间的转换都是 0 (下图中的对角线都是 0 ),即从 Employment → Employment 之间并不需要转换。比如我们可能认为从 Employment → Unemployment 之间的差距是最大的,故定义这个值为 3。与此同时,我们可能觉得从 Employment → Further Education 或者 Employment → Higher Education 之间虽然有区别,但区别也不大,就定义这两个值为 1 。注意,一般来讲,我们会认为两种状态之间的转变,不论是哪个方向的转变 (比如说从 Employment → Unemployment 对比从 Unemployment → Employment )的差距都是一样的,故下面的矩阵通常是对称的。我目前读的文献还未见过用不同值代表两个方向的转变,如果大家有兴趣的话也可以自己试试。
Employment | Further Education | Higher Education | Secondary Education | Training | Unemployment | |
---|---|---|---|---|---|---|
Employment | 0 | 1 | 1 | 2 | 1 | 3 |
Further Education | 1 | 0 | 1 | 2 | 1 | 3 |
Higher Education | 1 | 1 | 0 | 2 | 1 | 2 |
Secondary Education | 2 | 2 | 2 | 0 | 1 | 1 |
Training | 1 | 1 | 1 | 1 | 0 | 2 |
Unemployment | 3 | 3 | 2 | 1 | 2 | 0 |
以下命令用于生成基本的 sequence analysis 数据。
先来 reshape 一下数据。
*-先把数据转换成 long format
. reshape long state, i(id) j(order)
(note: j = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72)
Data wide -> long
-----------------------------------------------------
Number of obs. 712 -> 51264
Number of variables 86 -> 16
j variable (72 values) -> order
xij variables:
state1 state2 ... state72 -> state
-----------------------------------------------------
对数据进行 sqset
,将其设定为序列分析的数据专有格式,其目的和作用与面板分析中的 xtset
,以及时间序列分析中的 tsset
命令相似。
. sqset st id order
element variable: state, 1 to 6 /*6个state*/
identifier variable: id, 1 to 712
order variable: order, 1 to 72
看一看各种 sequence 样式的分布。
*-列表呈现
. sqtab, ranks (1/10) /*列出前10个最常见的 sequence样式*/
Sequence-Patte |
rn | Freq. Percent Cum.
---------------+-----------------------------------
1:72 | 40 39.22 39.22
4:26 3:46 | 13 12.75 51.96
5:24 1:48 | 11 10.78 62.75
2:24 1:48 | 7 6.86 69.61
4:27 3:45 | 6 5.88 75.49
1:2 2:10 1:60 | 5 4.90 80.39
1:2 2:22 1:48 | 5 4.90 85.29
4:39 3:33 | 5 4.90 90.20
6:2 1:70 | 5 4.90 95.10
6:2 5:22 1:48 | 5 4.90 100.00
---------------+-----------------------------------
Total | 102 100.00
*-描述性统计分析
. sqdes /*sequence concentration直观表示*/
# of observed sequences: 712
overall # of obs. elements: 6
max sequence length: 72
# of producible sequences: 1.064e+56
----------------------------------------------------------
Observations | Sequences % of observed Cum.
-------------+--------------------------------------------
1 | 505 70.92696 70.92696 /*有505个sequencey样式只出现了一次*/
2 | 28 3.932584 74.85955
3 | 7 .9831461 75.8427
4 | 7 .9831461 76.82584
5 | 5 .7022472 77.52808
6 | 1 .1404494 77.66853
7 | 1 .1404494 77.80898
11 | 1 .1404494 77.94943
13 | 1 .1404494 78.08988
40 | 1 .1404494 78.23033 /*有1种sequencey样式出现了40次*/
|
Total | 557 78.23034
----------------------------------------------------------
进一步,我们使用 egen
命令生成一些有用的变量。其他变量生成命令包括 sqelemcount()
sqepicount()
sqgapcount()
等等,可以通过 help sqegen
或者 help sqstat
找到更详细的说明。
/* () 中可以留空,这里是生成每条 sequence 的长度*/
. egen length = sqlength()
/*不过我们这里的所有 sequence 长度都是一样的*/
. tab length
Length of |
sequence | Freq. Percent Cum.
------------+-----------------------------------
72 | 51,264 100.00 100.00
------------+-----------------------------------
Total | 51,264 100.00
/*生成每条 sequence 中含有状态1(employment)的长度*/
. egen length1 = sqlength(), element(1)
/*id1的sequence里面,employment这个state出现了68次*/
. tab length1 if id == 1
Length of |
episodes of |
element 1 | Freq. Percent Cum.
------------+-----------------------------------
68 | 72 100.00 100.00
------------+-----------------------------------
Total | 72 100.00
每个 sequence 的组成都不同,计算两个 sequence 之间的不同的大小可以决定哪些 sequence 可以大致被分为一类。我这里讲两种距离计算的方法,一个用到了上面我们自定义的转换矩阵,另一个用的是用数据生成的矩阵。具体哪种方法更好呢,那就见仁见智啦。
先介绍第一种方法,用的就是我们自定义的转换矩阵。
. reshape wide state, i(id) j(order) /*先把数据 reshape 回 wide 格式*/
*-输入上述的自定义转换矩阵
#delimit ;
matrix mvdanes = (0,1,1,2,1,3 \
1,0,1,2,1,3 \
1,1,0,2,1,2 \
2,2,2,0,1,1 \
1,1,1,1,0,2 \
3,3,2,1,2,0 );
#delimit cr
set matsize 4000
/*用定义的 matrix 及 oma 算法,subsmat中就是我们定义的矩阵的名字*/
. oma state1-state72, subsmat(mvdanes) pwd(omd) length(72) indel(1.5)
下面用数据来生成转换矩阵,主要用到 trans2subs
这个命令。
/*用数据自己生成的转换矩阵来计算距离*/
. preserve
. reshape long state, i(id) j(m)
. trans2subs state, id(id) subs(tpr1)
. matrix list tpr1
symmetric tpr1[6,6]
c1 c2 c3 c4 c5 c6
r1 0
r2 1.147539 0
r3 1.064734 1.849958 0
r4 1.643575 1.757525 1.671111 0
r5 1.182927 1.844291 1.96 1.90181 0
r6 1.207729 1.525335 1.831594 1.803575 1.608297 0
. trans2subs state, id(id) subs(tpr2) diag
. matrix list tpr2
symmetric tpr2[6,6]
c1 c2 c3 c4 c5 c6
r1 0
r2 1.967601 0
r3 1.98727 1.993341 0
r4 1.984684 1.987531 1.982969 0
r5 1.959993 1.992045 1.999488 1.994867 0
r6 1.951231 1.96336 1.996033 1.985649 1.972029 0
. restore
/*再次使用 oma 算法及生成的矩阵 tpr 来计算距离*/
oma state1-state72, subsmat(tpr1) pwd(tpr) length(72) indel(1.5)
两个矩阵算出来的距离有什么区别吗?用 corrsqm
这个命令。
/*看看两种方法生成的 distance 是否相同*/
. corrsqm omd tpr
VECH correlation between omd and omv: 0.7726 /*correlation 还可以,不错!*/
简单起见,我们就选择用 omd 这个距离来对所有人进行 sequence 分组。具体分成几组好呢,我们可以根据理论来看,也可以画出 index plot 来看。
分组生成命令 clustermat
及 cluster generate
如下:
clustermat wards omd, name(oma) add
cluster generate o=groups(8 12) /*依次分成8组及12组;之后再看怎样分结果最好*/
tab o8
o8 Freq. Percent Cum.
1 93 13.06 13.06
2 139 19.52 32.58
3 62 8.71 41.29
4 146 20.51 61.80
5 93 13.06 74.86
6 30 4.21 79.07
7 47 6.60 85.67
8 102 14.33 100.00
Total 712 100.00
tab o12
o12 | Freq. Percent Cum.
------------+-----------------------------------
1 | 93 13.06 13.06
2 | 42 5.90 18.96
3 | 97 13.62 32.58 /*看来这里把上面的第2组劈开成了两组*/
4 | 62 8.71 41.29
5 | 89 12.50 53.79
6 | 57 8.01 61.80 /*这里把上面的第4组劈开成了两组*/
7 | 24 3.37 65.17
8 | 35 4.92 70.08
9 | 34 4.78 74.86 /*这里把上面的第5组劈开成了三组*/
10 | 30 4.21 79.07
11 | 47 6.60 85.67
12 | 102 14.33 100.00
------------+-----------------------------------
Total | 712 100.00
以分成八组为例的话,我们看看八组中每组的代表 sequence 长什么样子,即生成每组的 medoid sequence,主要用到 discrepancy
这个命令。
stripe state1-state72, gen(seqstr) symbols("EFHSTU") /*先生成seqstr变量,里面放入sequence的简化信息*/
list seqstr in 1/5, clean /*列出前5个sequence的样子*/
seqstr
1. TTEEEETTEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
2. UUFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
3. UUTTTTTTTTTTTTTTTTTTTTTTTTFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEUU
4. TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTEEEEEEEEEEEEEEUUUUUUUUU
5. UUFFFFFFFFFFFFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
discrepancy o8, dist(omd) id(id) dcg(dx) niter(1)
sort o8 dx
by o8: gen medoid = _n==1
list o8 dx seqstr if medoid, clean
o8 dx seqstr
1. 1 1.241993 EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
94. 2 3.936442 TTTTTTTTTTTTTTTTTTTTTTTTEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
233. 3 3.302549 FFFFFFFFFFFFFFFFFFFFFFFFFFFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
295. 4 6.059251 SSFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
441. 5 26.78911 TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTEEEEEEEEEEEEEEUUUUUUUUU
534. 6 8.887777 TTTTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
564. 7 7.227705 SSSSSSSSSSSSSSSSSSSSSSSSSSEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
611. 8 3.599865 SSSSSSSSSSSSSSSSSSSSSSSSSSHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
可以看出,如果分成八组的话,第一组的代表 sequence jiushi从头到尾一直是处于 employment 状态的人。
Sequence 图像主要有三大类,sqparcoord
, chronogram
,sqindexplot
,及 transition pattern graph。sqparcoord
可以画出出现频率比较高的 sequence。Chronogram 主要为了看出在每种 state 里面的持续时间。Indexplot 把每条 sequence 都化成了一条横线,然后叠加在一起看规律。Transition pattern graph 主要可以看出整体而言,每种 state 之间的转化情况。
sqparcoord
先来看看几条出现频率最高的 sequence 的样子吧!
preserve
reshape long state, i(id) j(order) /*sqparcoord只可以在 long format下使用,因此 reshape to long*/
sqparcoord, so offset(0.5) wlines(1) ylabel(1(1)6)
restore
可以看出呢,不少人一直处于 employment 状态(从头至尾都是状态 1)。也可以看出不少人从 状态5 (Training) 转换到 状态1。我随便改了改一些线条的颜色,因为我觉得彩色一点比较好看。
chronogram
chronogram state*, by(o8, legend(off)) name(chronogram, replace) /*用之前的分成的八组来生成 chronogram*/
我把 legend(off)
了……不过还是可以看出,第一组的话,蓝色代表 employment。
sqindexplot
sqindexplot
需要数据是 long format,因此要先把数据 reshape
一下。
cluster generate o999 = groups(750), name(oma) ties(fewer)
preserve
reshape long state, i(id) j(m)
sqset state id m
sqindexplot, by(o8, note("") ) order(o999) name(indexplot, replace)
restore
这次我保留 legend
了……
Transitional pattern graph 主要用到了 trprgr
这个命令。大家可以自己去试一下,这里就不展示了。
其他常见的生成变量包括每条 sequence 的熵,用到了 sqentropy
命令。也可以生成每个人在每个状态下的持续时间,用到 cumuldur
命令。或者可以算出每条 sequence 中有多少个 spell,用到 nspells
命令。语法复制如下,大家可以自己去尝试,这里就不细讲了。
/*计算Shannon entropy; 生成数字在[0,1]之间。若这条 sequence 包括了所有状态且每个状态 duration 相等的话,entropy = 1;如果只有一个状态,则entropy = 0*/
sdentropy state1-state72, gen(ent) cd(dur) nstates(6)
/*在每个状态下的持续时间*/
cumuldur state1-state72, cd(dur) nstates(6)
/*计算每条sequence中包括的spell数量*/
nspells state1-state72, gen(nsp)
欢迎大家用 Sequence Analysis 去做各种方向的研究哦。还有不少人用这个方法去研究音乐乐谱、跳舞规律、生活作息等等。如果可以和 network analysis 合并在一起研究的话,相信会碰撞出很好看的火花(也是现在社会学中很热门的研究方向之一)。
连享会-直播课 上线了!
http://lianxh.duanshu.com
免费公开课:
直击面板数据模型 - 连玉君,时长:1小时40分钟,课程主页 Stata 33 讲 - 连玉君, 每讲 15 分钟. Stata 小白的取经之路 - 龙志能,时长:2 小时,课程主页 部分直播课 课程资料下载 (PPT,dofiles等)
支持回看
专题 | 嘉宾 | 直播/回看视频 |
---|---|---|
⭐ 最新专题 | 因果推断, 空间计量,寒暑假班等 | |
⭕ 数据清洗系列 | 游万海 | 直播, 88 元,已上线 |
研究设计 | 连玉君 | 我的特斯拉-实证研究设计,-幻灯片- |
面板模型 | 连玉君 | 动态面板模型,-幻灯片- |
面板模型 | 连玉君 | 直击面板数据模型 [免费公开课,2小时] |
Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。
关于我们
课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法
等
连享会小程序:扫一扫,看推文,看视频……
扫码加入连享会微信群,提问交流更方便
✏ 连享会学习群-常见问题解答汇总:
✨ https://gitee.com/arlionn/WD
New!
lianxh
命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh