Sequence Analysis:生命历程中的序列分析

发布时间:2021-01-07 阅读 4772

Stata连享会   主页 || 视频 || 推文 || 知乎

温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。

New! lianxh 命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh

课程详情 https://gitee.com/arlionn/Course   |   lianxh.cn

课程主页 https://gitee.com/arlionn/Course

作者: Skylar B.Y. Sun

邮箱: sociology.tutor@gmail.com


目录


编者按: 本文主要编译自以下两篇文章,特此感谢!

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)。目前,常用的统计软件 RStata 都有序列分析相关的命令包,且 Stata 的命令相对更为丰富。因此,这篇就向大家介绍一下如何用 Stata 分析生命历程的数据。

1. Sequence 基本概念

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 的特点息息相关。与生存分析数据还有一个不同,即序列数据中没有风险比的这个概念。

2. sq.ado & sadi 命令安装

Stata 目前有两套主要用于 sequence analysis 的命令。请按照如下方式安装。

net from http://teaching.sociology.ul.ie/sadi
net install sadi  /*导入最新版本的 sadi 命令*/

ssc install moremata
ssc install sq /*主要用来画 sequence index plot*/

3. 数据导入

在下面的例子中,我们将使用 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

4. 自定义转换矩阵

虽然之后我们也会介绍一种通过数据信息自己生成的转换矩阵,但在不少研究中,很多学者依旧倾向于自定义转换矩阵。

定义转换矩阵的原则主要是基于作者对于不同状态之间差别的理解。比如说,同一个状态之间的转换都是 0 (下图中的对角线都是 0 ),即从 EmploymentEmployment 之间并不需要转换。比如我们可能认为从 EmploymentUnemployment 之间的差距是最大的,故定义这个值为 3。与此同时,我们可能觉得从 EmploymentFurther Education 或者 EmploymentHigher Education 之间虽然有区别,但区别也不大,就定义这两个值为 1 。注意,一般来讲,我们会认为两种状态之间的转变,不论是哪个方向的转变 (比如说从 EmploymentUnemployment 对比从 UnemploymentEmployment )的差距都是一样的,故下面的矩阵通常是对称的。我目前读的文献还未见过用不同值代表两个方向的转变,如果大家有兴趣的话也可以自己试试。

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

5. Sequence data 基本数据生成

以下命令用于生成基本的 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

6. 计算 sequence distance

每个 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 还可以,不错!*/

7. 生成不同聚类 (cluster)

简单起见,我们就选择用 omd 这个距离来对所有人进行 sequence 分组。具体分成几组好呢,我们可以根据理论来看,也可以画出 index plot 来看。

分组生成命令 clustermatcluster 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 状态的人。

8. Sequence 可视化

Sequence 图像主要有三大类,sqparcoordchronogramsqindexplot,及 transition pattern graph。sqparcoord 可以画出出现频率比较高的 sequence。Chronogram 主要为了看出在每种 state 里面的持续时间。Indexplot 把每条 sequence 都化成了一条横线,然后叠加在一起看规律。Transition pattern graph 主要可以看出整体而言,每种 state 之间的转化情况。

8.1 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。我随便改了改一些线条的颜色,因为我觉得彩色一点比较好看。

8.2 chronogram

chronogram state*, by(o8, legend(off)) name(chronogram, replace)  /*用之前的分成的八组来生成 chronogram*/

我把 legend(off) 了……不过还是可以看出,第一组的话,蓝色代表 employment。

8.3 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 这个命令。大家可以自己去试一下,这里就不展示了。

9. 其他变量生成

其他常见的生成变量包括每条 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

免费公开课:


课程一览

支持回看

专题 嘉宾 直播/回看视频
最新专题 因果推断, 空间计量,寒暑假班等
数据清洗系列 游万海 直播, 88 元,已上线
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
面板模型 连玉君 直击面板数据模型 [免费公开课,2小时]

Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。


关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。直播间 有很多视频课程,可以随时观看。
  • 连享会-主页知乎专栏,300+ 推文,实证分析不再抓狂。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法

连享会主页  lianxh.cn
连享会主页 lianxh.cn

连享会小程序:扫一扫,看推文,看视频……

扫码加入连享会微信群,提问交流更方便

✏ 连享会学习群-常见问题解答汇总:
https://gitee.com/arlionn/WD

New! lianxh 命令发布了:
随时搜索连享会推文、Stata 资源,安装命令如下:
. ssc install lianxh
使用详情参见帮助文件 (有惊喜):
. help lianxh