Stata:如何同时对多个数据框操作-frame

发布时间:2021-10-16 阅读 328

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

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

New! lianxh 命令发布了:
随时搜索推文、Stata 资源。安装:
. ssc install lianxh
详情参见帮助文件 (有惊喜):
. help lianxh
连享会新命令:cnssc, ihelp, rdbalance, gitee, installpkg

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

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

⛳ Stata 系列推文:

PDF下载 - 推文合集

作者:徐嘉树 (中国人民大学)
邮箱jiashuxu@ruc.edu.cn

编者按:本文主要摘译自下文,特此致谢!
Source:Fun with frames -Link-


目录


本文编译自 Stata Blog,作者 Chuck Huber 向我们展示了 frames 功能的具体应用。尽管很多用户相当喜欢 frames 功能,但是本文作者一开始对于 Stata 16 中这一新添功能并不感冒,直到他有一次同时需要处理 23 个数据集时,才体会到 frames 功能的好处所在。

在原文中,作者用包含病人信息、医院信息和染色体遗传信息的多个研究数据集,来展示怎样使用 frames 功能。遗憾的是,作者使用的部分研究数据并非开放数据。因此,我们在编译过程中参考了原文的思路和指令,但采用其他来源的数据进行操作,因此输出结果不尽相同。

接下来将从以下五个方面介绍 frames 功能:

  • 同时使用多个数据集;
  • frames 与后续估计;
  • frames 与 frval 的连接;
  • frames 与 frget 的连接;
  • 多个 frames。

1. 同时使用多个数据集

首先,我们利用 frame create 命令语句创建名为 patients1 的 frame,并调用名为 patients1 的数据集。

. frame create patients1
. frame patients1: use patients1

接着,继续创建另一个 frame,将它称之为 patients2,也是调用同名的数据集。

.  frame create patients2
.  frame patients2: use patients2

我们可以用 frame dir 来识别出存储中现有的三个数据框,第一个是 default,另外两个是我们刚刚创建的。我们还能直观地看到每个数据框中包含的数据集、样本量、变量数。

. frame dir
  default    0 x 0
  patients1  1772 x 14; patients1.dta
  patients2  1024 x 14; patients2.dta

现在我们可以利用 frame 前缀拟合一个线性回归模型,再用同样的指令拟合另一个数据集中同样的模型,并分别用 estimate store 将系数保存下来。

. frame patients1: regress sbp c.age##c.bmi
. estimates store patients1 
. frame patients2: regress sbp c.age##c.bmi
. estimates store patients2

然后直接用 estimates table 进行两个数据集运行模型的结果对比。

. estimates table patients1 patients2

----------------------------------------
    Variable | patients1    patients2   
-------------+--------------------------
         age |   .9977217    .97277459  
         bmi |  1.8253391    2.1873918  
             |
 c.age#c.bmi | -.01331291   -.01813435  
             |
       _cons |  51.727175    48.077782  
----------------------------------------

2. frames 与后续估计

在拟合模型之后,利用 margins 来估计并将预测值 predictions 保存在一个数据集中,之后利用 graph twoway contour 来绘图。以往我们的做法是关掉正在运行的数据集,重新打开 predictions 数据集。但是现在我们可以轻松地创建一个 frame 来加入 predictions 数据集。

. frame change patients1
. regress sbp c.age##c.bmi

      Source |       SS           df       MS      Number of obs   =     1,764
-------------+----------------------------------   F(3, 1760)      =     10.91
       Model |  66463.5776         3  22154.5259   Prob > F        =    0.0000
    Residual |  3574716.18     1,760  2031.08874   R-squared       =    0.0183
-------------+----------------------------------   Adj R-squared   =    0.0166
       Total |  3641179.76     1,763  2065.33169   Root MSE        =    45.068
------------------------------------------------------------------------------
         sbp |      Coef.   Std. Err.      t    P>|t|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
         age |   .9977217   .9175058     1.09   0.277    -.8017941    2.797237
         bmi |   1.825339   2.094022     0.87   0.383    -2.281694    5.932372
 c.age#c.bmi |  -.0133129   .0383641    -0.35   0.729    -.0885568     .061931
       _cons |   51.72718   50.30771     1.03   0.304    -46.94198    150.3963
------------------------------------------------------------------------------

. margins, at(age=(30(10)90) bmi=(10(5)40)) saving(predictions, replace)

使用 frame change 转到 patients1 数据中运行多个指令,我们先拟合模型,然后利用 margins 获得预测值。请注意下面这行指令的后面加了选项 saving (predictions, replace) ,意味着我们将预测值保存在了名为 predictions 的数据集中。

我们创建一个名为 contour 的新的数据框,转到 contour 之后调用 predictions 数据集。

. frame create contour
. frame change contour
. use predictions

这个数据集中的三个变量 _at1_at2_margin,分别表示年龄、身体质量指数 BMI (Body Mass Index) 和线性回归的预测。

. describe _at1 _at2 _margin

              storage   display    value
variable name   type    format     label      variable label
-------------------------------------------------------------------------------
_at1            byte    %9.0g                 age
_at2            byte    %9.0g                 bmi
_margin         float   %9.0g                 Linear prediction, predict()

. list _at1 _at2 _margin in 1/5

     +------------------------+
     | _at1   _at2    _margin |
     |------------------------|
  1. |   30     10   95.91834 |
  2. |   30     15   103.0481 |
  3. |   30     20   110.1779 |
  4. |   30     25   117.3076 |
  5. |   30     30   124.4374 |
     +------------------------+

我们对变量重新命名后,绘制一个根据年龄和身体质量指数预测舒张压 SBP (Systolic Blood Pressure) 的等高线图。

. rename _at1 age
. rename _at2 bmi
. rename _margin pr_sbp

. twoway (contour pr_sbp bmi age, ccuts(90(10)170)),  ///
>        xlabel(30(10)90)  ylabel(10(5)40, angle(horizontal)) ///
>        xtitle("Age (years)") ///
>        ytitle("BMI")         ///
>        ztitle("Predicted Systolic Blood Pressure") ///
>        title("Predicted SBP by Age and BMI")

3. frames 与 frval 的连接

我们可以使用 frlink 来连接两个数据框。创建名为 community 的 frame,并调用同名数据集 community

. frame create community
. frame change community
. use community
. list cid cominc in 1/5, abbrev(10)

     +---------------+
     | cid    cominc |
     |---------------|
  1. |   1   1.0e+04 |
  2. |   2   5.0e+04 |
  3. |   3   5.0e+04 |
  4. |   4   1.2e+04 |
  5. |   5   9.0e+03 |
     +---------------+

这个 community 数据中包含表示社区编号的变量 cid 和表示过去一年社区人均净收入的变量 cominc。前面使用过的 patients1 数据中则包含表示个人年收入的变量 perinc,也包含表示个人属于哪个社区的变量 cid

. frame change patients1
. list pid cid perinc in 1/5, abbrev(10)

     +---------------------+
     | pid   cid    perinc |
     |---------------------|
  1. |   1   326   2.0e+04 |
  2. |   2   326   1.3e+04 |
  3. |   3   325       276 |
  4. |   4   325      7200 |
  5. |   5   325   2.4e+04 |
     +---------------------+

我们使用 frlinkpatients1community 两个数据框连接起来。因为每个 cidpatient1 数据框中出现多次,但是在 community 数据框中只出现一次。所以我们可以明确这是多对一的连接,即 frlink m:1。逗号后面的 frame (community) 说明 frlink 是将 community 数据框连接到当前的 patients1 数据框上。

. frlink m:1 cid, frame(community)

这样一来,我们的数据框就连接在一起了。我们利用 frval () 来获取当前数据框以外的其他数据框中变量的取值。比如,我们想要计算一下每个受访者个人年收入相对于社区人均净收入的比值。我们可以生成一个名为 rel_inc 的新变量,它表示当前 patient1 数据框中的个人年收入 perinc 除以 community 数据框中社区人均净收入 cominc 得到的比值。利用 frval (community, cominc) 就能够获取 community 数据框中变量 cominc 的值。

. generate rel_inc = perinc / frval(community, cominc)
. list pid cid cominc perinc rel_inc in 1/5, abbrev(16)

     +------------------------------------------+
     | pid   cid    cominc    perinc    rel_inc |
     |------------------------------------------|
  1. |   1   326   2.8e+03   2.0e+04   7.272727 |
  2. |   2   326   2.8e+03   1.3e+04   4.727273 |
  3. |   3   325   1.1e+03       276   .2509091 |
  4. |   4   325   1.1e+03      7200   6.545455 |
  5. |   5   325   1.1e+03   2.4e+04   21.81818 |
     +------------------------------------------+

如上表中的第三个人 (pid=3),所在社区编号 325 的人均净收入为 1100 元,而他个人的年收入为 276 元,变量 rel_inc 的取值 0.25,意味着这个人的个人年收入比 325 社区人均净收入低 75%。

4. frames 与 frget 的连接

另外,我们也可以用 frget 来复制连接在一起的其他 frame 中的变量。举个例子,我们有一个名为 long 的纵向数据集,其中包含追踪受访者三期的数据,即每个受访者有三期的身体质量指数 bmi 和舒张压 sbp 信息。下面让我们来给这个数据创建一个新的同名 frame。

. frame create long
. frame change long
. use long
. list in 1/10, abbrev(10)

     +--------------------------------+
     | pid   j        bmi   age   sbp |
     |--------------------------------|
  1. |   1   1    19.5325    45   108 |
  2. |   1   2    19.5325    45   108 |
  3. |   1   3    19.5325    45   110 |
  4. |   2   1   22.53906    49    96 |
  5. |   2   2   22.53906    49   104 |
     |--------------------------------|
  6. |   2   3   22.53906    49   108 |
  7. |   3   1   25.29938    82   163 |
  8. |   3   2   25.29938    82   174 |
  9. |   3   3   25.29938    82   182 |
 10. |   4   1   24.53125    57   147 |
     +--------------------------------+

我们想要利用这三期追踪数据拟合一个多层模型,并调节性别的影响。表示性别的变量 male 保存在数据框 patients1 中,让我们用 frlink 将两个数据框连起来。

. frlink m:1 pid, frame(patients1)

接下来,我们就可以用 frget 来复制变量 male 了,将它从 patients1 数据框中复制到当前 long 数据框。

. frget male, from(patients1)
. list in 1/10, abbrev(10)

     +---------------------------------------------------+
     | pid   j        bmi   age   sbp   patients1   male |
     |---------------------------------------------------|
  1. |   1   1    19.5325    45   108           1      1 |
  2. |   1   2    19.5325    45   108           1      1 |
  3. |   1   3    19.5325    45   110           1      1 |
  4. |   2   1   22.53906    49    96           2      1 |
  5. |   2   2   22.53906    49   104           2      1 |
     |---------------------------------------------------|
  6. |   2   3   22.53906    49   108           2      1 |
  7. |   3   1   25.29938    82   163           3      1 |
  8. |   3   2   25.29938    82   174           3      1 |
  9. |   3   3   25.29938    82   182           3      1 |
 10. |   4   1   24.53125    57   147           4      0 |
     +---------------------------------------------------+

这样我们就可以拟合多层模型了。

. mixed sbp i.male c.age##c.bmi || pid:, nolog noheader

------------------------------------------------------------------------------
         sbp |      Coef.   Std. Err.      z    P>|z|     [95% Conf. Interval]
-------------+----------------------------------------------------------------
      1.male |   2.039036   2.435889     0.84   0.403    -2.735219    6.813291
         age |   .6067942   .9697704     0.63   0.532    -1.293921    2.507509
         bmi |    1.03139   2.212426     0.47   0.641    -3.304886    5.367665
             |
 c.age#c.bmi |  -.0003429   .0405329    -0.01   0.993    -.0797859    .0791002
             |
       _cons |   72.64936   53.15391     1.37   0.172     -31.5304    176.8291
------------------------------------------------------------------------------

------------------------------------------------------------------------------
  Random-effects Parameters  |   Estimate   Std. Err.     [95% Conf. Interval]
-----------------------------+------------------------------------------------
pid: Identity                |
                  var(_cons) |   2085.381   76.46401      1940.773    2240.764
-----------------------------+------------------------------------------------
               var(Residual) |   545.5202   12.98857      520.6479    571.5807
------------------------------------------------------------------------------
LR test vs. linear model: chibar2(01) = 3875.23       Prob >= chibar2 = 0.0000

5. 多个 frames

开头我们说到过,作者喜欢 frames 的主要原因是一次同时处理 23 个数据集。这次数据处理就是使用了包含 22 条染色体遗传信息的 22 个数据集和病人其他信息的 1 个数据集。这些遗传信息数据集中的每一个数据都很大,大到需要 Stata MP 版本才能打开。

我们平时使用的 Stata 一般是 SE 版本,因为我既没有 MP 版本的软件,也没有作者使用的遗传信息数据,所以这部分的内容没有实际操作,只是解释一下作者的做法。

他在 MP 版本中先是利用 set segmentsize 来分配内存,然后用 set maxvar 将允许的最大变量数从默认值 5000 更改为 80000 ,这样才打开第一个染色体数据集 chromosome1

打开数据后,利用上文提到的 frlinkfrget 等功能连接数据框并从其他数据框复制所需变量。之后用 dsregress 拟合出一个因变量为舒张压,含有年龄、性别、身体质量指数等自变量的 Lasso 模型。最重要的是,这个模型中控制了超过七万个表示遗传信息的变量。正是这一点,让作者对 frames 功能大吃一惊。

作者还写了一个循环进一步探索是否还有更大的使用空间,他用 Stata 同时打开了这些数据集中超过 90 万个变量。试着想一想, Stata MP 版本最多同时设置 100 个数据框,也就是说理论上能够同时使用 1200 万个变量,这就是 Stata 16 中 frames 功能能做到的!

6. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh 合并, m
安装最新版 lianxh 命令:
ssc install lianxh, replace

相关课程

免费公开课

最新课程-直播课

专题 嘉宾 直播/回看视频
最新专题 文本分析、机器学习、效率专题、生存分析等
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
面板模型 连玉君 直击面板数据模型 [免费公开课,2小时]
  • Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。

课程主页

课程主页

关于我们

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

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

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

✏ 连享会-常见问题解答:
https://gitee.com/lianxh/Course/wikis

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