Stata: gen 命令中的 group() 函数的潜在风险| 连享会主页

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

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

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

作者:连玉君 ( lianxh.cn )


目录

  • 1. 问题背景

    • 一个小例子

  • 2. 揭秘:group() 函数的工作原理

    • 2.1 同类问题

    • 2.2 小结

  • 3. 解决方法

    • 使用 xtile 命令

  • 相关课程

    • 课程一览


1. 问题背景

我们经常使用 generate (后文简称 gen) 命令提供的 group() 函数对某个变量进行分组,产生分组变量 gg,继而基于 gg 变量进行后续的分组回归分析。

例如,在公司金融中,常用如下代码产生融资约束的分组指标:

*-用公司规模衡量融资约束,分成三组. bysort code: egen av_size = mean(size). sort av_size. gen gg = group(3). gen  FC = (gg==1)     //小规模公司定义为 FC 组. replace FC=. if gg==2 //丢弃中间组 . reg y x if FC==0. est store m_FC. reg y x if FC==1. est store m_NFC. esttab m_FC m_NFC

恐怖的事情就要发生了!

后续做分组回归时,你会发现:执行相同的代码,但两次得到的结果居然不同!

原因何在??


一个小例子

我先虚构一份数据,让各位了解 group() 函数的工作原理,搞明白这件事情后,上面的问题就迎刃而解了。

这份数据很简单,只有 4 行观察值。我们对变量 x 排序后再执行 gen g = group(2) 命令,以便将样本分成两组。为了测试分组结果是否唯一\稳定,我进一步使用 tatstat 命令计算了两组的均值。

clear  input x    y         3   13         2   10        1    1         2    8 end  sort x            \\ 由小到大排序 gen g = group(2)  \\ 等分两组 tabstat x y, by(g) f(%3.1f) sort g x y list, sepby(g) noobs

第一轮执行的结果如下:

. tabstat x y, by(g) f(%3.1f)Summary statistics: mean  by categories of: g        g |         x         y---------+--------------------       1 |       1.5       5.5       2 |       2.5      10.5---------+--------------------   Total |       2.0       8.0------------------------------. sort g x y. list, sepby(g) noobs  +------------------+  |  id   x    y   g |  |------------------|  | 301   1    1   1 |  | 201   2   10   1 |  |------------------|  | 401   2    8   2 |  | 101   3   13   2 |  +------------------+

可以看到,g 取值为 1 和 2 时两组的均值分别为 5.5 和 10.5,差为 5。

我又连续执行了两遍上述代码,结果都没有任何变化,似乎表明上述分组结果是稳定的。

然而,当我执行第四次时,得到了如下结果:

.  tabstat x y, by(g) f(%3.1f)Summary statistics: mean  by categories of: g        g |         x         y---------+--------------------       1 |       1.5       4.5       2 |       2.5      11.5---------+--------------------   Total |       2.0       8.0------------------------------.  sort g x y.  list, sepby(g) noobs  +------------------+  |  id   x    y   g |  |------------------|  | 301   1    1   1 |  | 401   2    8   1 |  |------------------|  | 201   2   10   2 |  | 101   3   13   2 |  +------------------+

此时,两组的均值分比为 4.5 和 11.5,差为 7。

留给诸位 2 分钟,对比一下两组结果,然后想想为什么会出现结果不一致的现象?

2. 揭秘:group() 函数的工作原理

细心的读者已经发现了结果发生漂移的原因:id=201 和 id=401 的两个观察值的 x 变量具有相同的取值,x=2。然而,他们的 y 变量取值却不同。当我们执行 sort x 命令对 x 变量进行排序时,id=201 会随机地被排在第二位或第三位。虽然这对 x 的排序结果没有任何影响,但 y 变量中各个观察值出现的顺序却存在差异。

让我们更细致地解读一下 group() 函数的工作原理。

上面的分析中我们用到了如下两条核心命令:

sort x            \\ 由小到大排序 gen g = group(2)  \\ 等分两组

也就是说,gen 命令下的 group() 函数按如下两个步骤工作:

  • Step 1: 使用 sort 命令对样本进行排序;
  • Step 2: 将观察值平均分配为两组 (group(2))。比如,上例中样本数 N=4,那么排序后的第 1 个和第 2 个观察值就被分到第一组 (gg=1),第 3 和 4 个观察值被分到第二组 (gg=2)。

显然,某个观察值被分到第一组还是第二组,并不是由 group() 函数决定的,而是它之前的 sort 命令决定的。

如果诸位此时输入 help sort 命令查看其帮助文件,就会发现他有一个唯一的选项——stable(我用了十几年的 Stata,今天才发现原来 sort 命令还有选项!)

执行 sort x 时,如果不加入 stable 选项,那么就会随机出现如下两种情形中的一种:

CaseA          Case_B -----------  -----------  x    y     |     x   y  1    1     |     1   1  2   10     |     2   8  2    8     |     2  10   3   13     |     3  13 -----------  -----------

这就是我们此前看到的两种情形。

加入 stable 选项后,每次执行 sort x 后得到的结果都是相同的,即 Case A (它维持了原始数据中 y 变量各个观察值的相对顺序)。

其实,上述表述并不严谨,sort x, stable 其实上只是帮助我们维持在执行 sort 命令前一刻内存中数据的相对状态。然而,如果在 sort 命令之前执行过会打乱样本中各个观察值相对位置的命令,即使在 sort 命令中附加 stable 选项,仍然无法保证排序结果的稳定性,也就无法保证 group() 函数分组的唯一性。

有兴趣的读者可以执行如下命令测试一下。

clear  input x    y         3   13         2   10        1    1         2    8 end  rsort // 外部命令,随机排序,使用 ssc install rsort 下载 sort x, stable   gen g = group(2) tabstat x y, by(g) f(%3.1f) sort g x y list, sepby(g) noobs

当然,实证分析中很少有人会使用上例中的 rsort 命令主动打乱观察值顺序 (一个典型的特例是在 PSM 分析中使用最近邻匹配时,需要预先打乱观察值顺序)。更一般的情形是如下命令 (你在毫不自知的情况下打乱了样本顺序):

bysort industry year: egen av_x = mean(x)  sort av_x, stablegen g_x = group(10)……

2.1 同类问题

其实,当分组变量本身存在较多重复值时,egen 命令提供的 pctile() 函数,以及 quantiles 命令都存在上述问题,因为背后的道理都是相同的。

下面是针对 quantiles 命令的测试代码,也会存在结果不稳定的问题。

clear  input x    y         3   13         2   10        1    1         2    8 end   quantiles x, gen(gg) n(2)  tabstat x y, by(g) f(%3.1f) sort g x y list, sepby(g) noobs

2.2 小结

  • 如果用于分组变量存在诸多重复值,就非常容易导致上述问题;
  • 上例中,x 变量只有一个重复值 (数值 2 重复出现了两次),极端状况是 x 的所有观察值都集中于某一个取值,那么此时使用 group() 函数进行分组,就相当于随机分组,可能每次的结果都会不同。有兴趣的读者可以反复运行一下如下代码:
clear  input x    y         2   13         2   10        2    1         1    8       2   12 end  sort x  gen g = group(2) tabstat x y, by(g) f(%3.1f) sort g x y list, sepby(g) noobs

3. 解决方法

狭义而言,这个问题无解。

实证分析中的建议就是:

  • 如果分组变量本身有很多重复值,那么使用 group() 函数进行分组是非常糟糕的选择。Note:类别变量 (如教育水平)、计数变量 (如教育年限, 专利个数等) 都会存在很多重复值。此时最好是人为地事先设定分组界点,比如教育年限低于 12 年定义为「Low」,高于 12 年定义为「High」。
  • 如果分组变量是连续变量,如公司规模 (ln(总资产))、负债率等,出现重复值的概率很小,此时可以使用 generate 命令下的 group() 函数,但更好的办法是使用 quantiles 命令,基于分位数进行分组。但需要注意的是,quantiles 命令在样本数太小或分组个数太小时都不适用。
  • 更好的办法是基于分位数分组 (但分组结果不再保证每组的样本数相当近似相等),此时可以开始用 xtile,或 egen 命令下的 pctile() 函数。

使用 xtile 命令

由于 xtile 基于分位数分组,使用 sum x, detail 命令可知,x 变量的中位数是 2,因此,xitle gg=x, n(2) 会以 x=2 为分界点 (cutpoint) 将样本分成两组,用新生成的变量 gg 加以标记。此时,分组结果并不均等,这在小样本中是非常普遍的事情,对于大样本而言,组间样本数的差异基本上可以忽略。

对于前文提到的类别变量,或续别变量,我们可以使用 xtile 命令的 cutpoints() 选项人为设定分界点,此处不再赘述。也可以使用 egen 命令中的 cut() 函数实现相似的目的,缺陷是此时无法配合使用 bysort 前缀。

clear  input id    x    y         101   3   13         201   2   10        301   1    1         401   2    8 end   xtile gg = x, n(2) // New tabstat x y, by(g) f(%3.1f) sort g x y list, sepby(g) noobs

结果如下:

.  tabstat x y, by(g) f(%3.1f)Summary statistics: mean  by categories of: gg (2 quantiles of x)      gg |         x         y---------+--------------------       1 |       1.7       6.3       2 |       3.0      13.0---------+--------------------   Total |       2.0       8.0------------------------------.  sort g x y.  list, sepby(g) noobs   +-------------------+  |  id   x    y   gg |  |-------------------|  | 301   1    1    1 |  | 401   2    8    1 |  | 201   2   10    1 |  |-------------------|  | 101   3   13    2 |  +-------------------+

相关课程

连享会-直播课 上线了!
http://lianxh.duanshu.com

免费公开课:


课程一览

支持回看,所有课程可以随时购买观看。

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

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

(0)

相关推荐

  • GDB高级技巧:边Debug边修复BUG,无需修改代码,无需重新编译

    引言 程序调试时,你是否遇到过下面几种情况: 1.经过定位,终于找到了程序中的一个BUG,满心欢喜地以为找到了root cause,便迫不及待地修改源码,然后重新编译,重新部署.但验证时却发现,真正的 ...

  • order by和group by的区别

    order by: 用来对数据库的一组数据进行排序   desc:降序   asc:升序 group by: "By"指定的规则对数据进行分组,所谓的分组就是将一个"数据 ...

  • Stata: 不可不知的4种断点回归 (RDD) 中的平滑性检验方法

    Stata: 不可不知的4种断点回归 (RDD) 中的平滑性检验方法 断点回归由Thistlewaite and Campbell(1960)首次使用,但直到1990年代末才引起经济学家的重视.Thi ...

  • Stata:gen命令中的group()函数的潜在风险

    原文链接:https://www.lianxh.cn/news/56d6e46376d31.html 目录 1. 问题背景 一个小例子 2. 揭秘:group() 函数的工作原理 2.1 同类问题 2 ...

  • 【独家】CDER是如何评估药物中使用纳米材料所带来潜在风险的?

    距离<2017中国医药创新高峰论坛>召开还剩4天! 一.介绍 纳米技术目前作为开发创新产品的手段而正在制药行业应用,包括新剂型,复杂传递系统和靶向治疗.纳米技术在医药行业中的应用可以使药物 ...

  • Linux命令中交互式命令都有哪些?Linux基础

    交互式命令就是在top命令执行过程中使用的一些命令.top命令用于实时地对系统处理器状态进行监控,它能够实时地显示系统中各个进程的资源占用状况.该命令可以按照CPU的使用.内存的使用和执行时间对系统任 ...

  • 分享:HR做薪酬核算时,Excel中常用的函数和功能

    薪酬核算与发放流程 "发工资"是每个企业中很日常和普通的事,也是员工的大事.如果"发工资"这件事没有做好,则很容易引起员工的不满,甚至产生劳动纠纷.因此,如何规 ...

  • AI中的封套扭曲命令中的变形工具如何操作

    AI中的封套扭曲命令里面有一个变形的操作,如何来使用呢?下面来看看具体的操作方法. 1.首先我们导入素材图片到AI软件的画板中,然后点击嵌入按钮. 2.之后选中图片,点击对象封套扭曲中的变形建立选项. ...

  • AI中的封套扭曲命令中的顶层对象如何操作

    在ai软件的封套扭曲命令中有一个顶层对象建立,这个应用比较广泛,下面来看看操作方法. 1.首先我们要准备好素材,并用钢笔绘制出一个形状来. 2.将形状放到图片上方,将两者全部选中,点击对象选项卡. 3 ...

  • AI中的封套扭曲命令中的网格工具如何操作

    AI软件中的封套扭曲命令有一个网格工具如何操作呢?这个类似于ps 中的变形工具,下面来看看操作方法. 1.首先我们导入图片素材,点击封套扭曲选项. 2.然后在它的子菜单中点击--用网格建立的选项. 3 ...

  • Excel表格中求差函数公式怎么样使用

    在excel在使用中有时需要求两个数据的差,该怎么做呢?下面给大家分享Excel表格中求差函数公式的使用. 材料/工具 电脑,excel 方法 1 首先在电脑上找到Excel工作表. 2 双击点开ex ...

  • 在Excel中像使用函数一样优雅的使用正则表达式

    从杂乱的数据中提取数值.提取字母.汉字这样的需求,实在是太常见了,我浏览论坛几乎每天都可以看到很多,以至于我想Excel应该有一个这样的函数.但是没有,于是我自己写了一个,也是为了方便在Excel中练 ...