从 Stata 到 R:如何使用 tag() 和 if_else() 标记分组中的首个观测

文摘   教育   2024-11-06 22:00   山西  

👇 连享会 · 推文导航 | www.lianxh.cn

🍓 课程推荐:2024 机器学习与因果推断专题
主讲老师:司继春 (上海对外经贸大学) ;张宏亮(浙江大学)
课程时间:2024 年 11 月 9-10 日 ;16-17日
课程咨询:王老师 18903405450(微信)

课程特色 · 2024机器学习与因果推断

  • 懂原理、会应用。本次课程邀请了两位老师合作讲授,目的在于最大限度地实现理论与应用的有机结合。为期四天的课程,分成两个部分:第一部分讲解常用的机器学习算法和适用条件,以及文本分析和大语言模型;第二部分通过精讲 4-6 篇发表于 Top 期刊的论文,帮助大家理解各类机器学习算法的应用场景,以及它们与传统因果推断方法的巧妙结合。
  • 以 Top 期刊论文为范例。目前多数人的困惑是不清楚如何将传统因果推断方法与机器学习结合起来。事实上,即便是 MIT 和 Harvard 的大牛们也都在「摸着石头过河」。为此,通过论文精讲和复现来学习这部分内容或许是目前最有效的方式了。张宏亮老师此前在浙江大学按照这一模式教授了「因果推断和机器学习」课程,效果甚佳:学生们能够逐渐建立起研究设计的理念,并在构造识别策略时适当地嵌入机器学习方法。

温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」。或直接长按/扫描如下二维码,直达原文:

作者: 连玉君 (中山大学)
邮箱: arlionn@163.com

1. 引言

在数据处理中,我们常常需要标记每个分组中的首个观测值。比如,在清洗创业投资数据时,我们需要从多个投资方中找出「领投」公司,并加以标记;在处理上市公司数据时,需要找出公司首次出现在数据库中的会计年份。

Stata 提供了简单易用的 egen tag() 函数,可以高效地完成分组标记;而在 R 中,虽然没有直接提供实现此功能的函数,但借助 dplyr 包中提供的 group_by()mutate() 函数,并结合 if_else() 函数也能实现相同的操作。

本文将通过两个实例来演示在 Stata 和 R 中如何实现分组标记。

2. 示例数据

本文所用的示例数据框包括以下变量:

group1group2value
1A10
1A20
2B30
2B40
2A50
3C60
3C70
4A80

其中:

  • group1 是数值型分组变量,
  • group2 是字符型分组变量,代表另一种分组方式。

3. Stata 代码实现

在 Stata 中,我们可以使用 egen tag() 函数来创建分组标签变量 tag1tag2。以下代码段实现了按 group1group2 分组的首个观测标记:

* 创建示例数据
clear
input group1 str1 group2 value
1 "A" 10
1 "A" 20
2 "B" 30
2 "B" 40
2 "A" 50
3 "C" 60
3 "C" 70
4 "A" 80
end

* 按 group1 分组创建标签
egen tag1 = tag(group1)

* 按 group2 分组创建标签
egen tag2 = tag(group2)

* 查看结果
order group1 tag1 group2 tag2 value
list, clean

代码解读:

  • egen tag1 = tag(group1):使用 tag(group1) 来生成标签变量 tag1,在每个 group1 分组中,第一个观测被标记为 1,其他观测为 0。
  • bysort group2: egen tag2 = tag(group2):类似地,按 group2 分组生成标签变量 tag2

输出结果如下:

. list, clean

group1 tag1 group2 tag2 value
1. 1 1 A 1 10
2. 1 0 A 0 20
3. 2 1 B 1 30
4. 2 0 B 0 40
5. 2 0 A 0 50
6. 3 1 C 1 60
7. 3 0 C 0 70
8. 4 1 A 0 80

4. R 代码实现

在 R 中,我们使用 dplyr 包的 group_by()mutate() 函数,结合 if_else()row_number() 来实现相同的分组标记效果。代码如下:

library(tidyverse)

# 创建示例数据框
df <- data.frame(
  group1 = c(11222334),
  group2 = c("A""A""B""B""A""C""C""A"),
  value = c(1020304050607080)
)

# 按 group1 分组创建 tag1
df_tagged <- df %>%
  group_by(group1) %>%
  mutate(tag1 = if_else(row_number() == 110)) %>%
  ungroup()

# 按 group2 分组创建 tag2
df_tagged <- df_tagged %>%
  group_by(group2) %>%
  mutate(tag2 = if_else(row_number() == 110)) %>%
  ungroup()

# 打印结果
df_tagged |> 
  relocate(group1, tag1, group2, tag2, value) |> 
  print(n=8)

输出结果如下:

# A tibble: 8 × 5
  group1  tag1 group2  tag2 value
   <dbl> <dbl> <chr>  <dbl> <dbl>
1      1     1   A      1    10
2      1     0   A      0    20
3      2     1   B      1    30
4      2     0   B      0    40
5      2     0   A      0    50
6      3     1   C      1    60
7      3     0   C      0    70
8      4     1   A      0    80

4.1 代码解读

  • group_by(group1):按 group1 分组。
  • mutate(tag1 = if_else(row_number() == 1, 1, 0)):使用 if_else() 函数创建标签 tag1,当 row_number() == 1 时,表示该观测是分组的第一个观测。
  • ungroup():解除分组,以便后续按 group2 进行分组操作。
  • group_by(group2)mutate(tag2 = if_else(row_number() == 1, 1, 0)):按 group2 分组生成标签 tag2

4.2 if_else() 函数详细说明

if_else()dplyr 包中用于条件判断的函数,与 base R 中的 ifelse() 类似,但具有更严格的类型一致性要求,更适合数据处理:

  • if_else(row_number() == 1, 1, 0):在每组数据的首个观测值时返回 1,否则返回 0。
  • 类型一致性if_else() 要求 true_valuefalse_value 的类型一致,避免不必要的类型转换。
  • 性能优化:在数据管道中,if_else()ifelse() 处理大数据更有效率。

使用 if_else() 可以在 mutate() 中快速进行分组条件判断,帮助灵活生成新的标记变量。详情参见 dplyr - if_else(),以及 R: The Difference Between ifelse() vs. if_else()。

5. 实例:创建「领投」变量

假如手头有一份创新投资数据,包含「投资方」和「被投企业」两个变量。我们的任务是创建一个新变量 leader_invest (是否为「领投」企业)。


投资方被投企业leader_invest
1复星资本 (领投)金多多1
2复星医药金多多0
3同创伟业金多多0
4天使湾创投小象生活1
5众談资本奥麦星球1
6大华投资汝乐1
7电魂创投汝乐0
8天天资本汝乐0
9华盖资本 (领投)礼邦医药1
10诺瑾资产(领投)礼邦医药1
11悬方资本礼邦医药0
12千杉云帆资产礼邦医药0

经过分析,我们可以按照如下思路生成 leader_invest 变量,以标记投资方中的“领投企业”:

  1. 条件1:如果 投资方 中包含 (领投),则标记 leader_invest = 1
  2. 条件2:如果不满足条件1,但 被投企业 只有一个投资方,则标记 leader_invest = 1
  3. 条件3:如果以上条件都不满足且 被投企业 有多个投资方,则将每组中的第一个投资方视为“领投”,即 leader_invest = 1

我们将分别用 Stata 和 R 代码实现这一目标。

5.1 Stata 代码实现

在 Stata 中,我们可以使用 tag() 函数配合 egen 和分组排序的逻辑判断,实现领投标记。代码如下:

* 1. 输入数据
clear
input str40 投资方 str15 被投企业
"复星资本(领投)" "金多多"
"复星医药" "金多多"
"同创伟业" "金多多"
"天使湾创投" "小象生活"
"众麟资本" "奥麦星球"
"大华投资" "汝乐"
"电魂创投" "汝乐"
"天天资本" "汝乐"
"华盖资本(领投)" "礼邦医药"
"诺瑾资产(领投)" "礼邦医药"
"幂方资本" "礼邦医药"
"千杉云帆资产" "礼邦医药"
end

gen id = _n // 记录原始序号

* 2. 创建 leader_invest 变量
gen leader_invest = 0
replace leader_invest = 1 if strpos(投资方, "(领投)") > 0 // 条件 1
bysort 被投企业: replace leader_invest = 1 if _N == 1 // 条件 2
sort id // 这一步很重要
egen tag_first = tag(被投企业)
replace leader_invest = 1 if (tag_first==1) & (leader_invest==0) // 条件 3

关键代码解读如下:

  1. 条件1:使用 strpos() 函数检查“(领投)”标记,满足的记录直接设为 leader_invest = 1
  2. 条件2:按 被投企业 分组,通过 _N 判断分组内是否只有一个投资方,若是则设 leader_invest = 1
  3. 条件3:按 被投企业 分组排序,将分组内的第一个投资方设为领投,同时排除已标记记录。

最终结果如下:

. sort id 

. list 投资方 被投企业 leader_invest, clean

                 投资方   被投企业   leader~t  
       ---------------------------------------          
  1.   复星资本(领投)      金多多          1  
  2.           复星医药     金多多          0  
  3.           同创伟业     金多多          0  
       ---------------------------------------
  4.         天使湾创投   小象生活          1  
       ---------------------------------------
  5.           众麟资本   奥麦星球          1 
       --------------------------------------- 
  6.           大华投资       汝乐          1  
  7.           电魂创投       汝乐          0  
  8.           天天资本       汝乐          0 
       --------------------------------------- 
  9.   华盖资本(领投)    礼邦医药          1  
 10.   诺瑾资产(领投)    礼邦医药          1  
 11.           幂方资本   礼邦医药          0  
 12.       千杉云帆资产   礼邦医药          0  

5.2 R 代码实现

在 R 中,我们使用 dplyr 包的 tribble() 函数录入示例数据,并基于条件生成 leader_invest 变量。

# 加载必要的包
library(dplyr)
library(stringr)
library(tibble)

# 示例数据
data <- tribble(
  ~投资方,               ~被投企业,
  "复星资本(领投)",     "金多多",
  "复星医药",             "金多多",
  "同创伟业",             "金多多",
  "天使湾创投",           "小象生活",
  "众麟资本",             "奥麦星球",
  "大华投资",             "汝乐",
  "电魂创投",             "汝乐",
  "天天资本",             "汝乐",
  "华盖资本(领投)",     "礼邦医药",
  "诺瑾资产(领投)",     "礼邦医药",
  "幂方资本",             "礼邦医药",
  "千杉云帆资产",         "礼邦医药"
)

# 生成 leader_invest 变量
data <- data %>%
  group_by(被投企业) %>%
  mutate(
    leader_invest = case_when(
      str_detect(投资方, "(领投)") ~ 1,     # 条件1:包含“(领投)”
      n() == 1 ~ 1,                          # 条件2:只有一个投资方
      row_number() == 1 ~ 1,                 # 条件3:第一个投资方
      TRUE ~ 0
    )
  ) %>%
  ungroup()

# 查看结果
view(data)

关键代码解释如下:

  1. 数据录入:使用 tribble() 简洁地输入示例数据。
  2. 条件判断:分组后依次判断三个条件,并使用 case_when()str_detect() 实现条件逻辑。

最终输出结果如下:

20241031184013

5. 小结

本文展示了如何在 R 和 Stata 中分别实现分组标记。Stata 提供了直接的 tag() 函数,操作简单直观;而在 R 中,可以借助 dplyr 包的 group_by()mutate()if_else() 函数组合来实现类似效果。这些方法能够有效标记分组中的首个观测,适用于数据筛选、去重和分组统计等场景。

6. 参考资料

  • Hadley Wickham, & Romain François. (2016). dplyr: A Grammar of Data Manipulation. 链接, PDF, Google
  • R Documentation on if_else(): 链接
  • [D] egen - tag(varlist)

7. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh _n 分组, md0 nocat
安装最新版 lianxh 命令:
ssc install lianxh, replace

  • 梁淑珍, 2022, Stata编程:_n 和 _N 有啥区别?, 连享会 No.1052.
  • 云锋, 2020, sumup:快速呈现分组统计量, 连享会 No.65.
  • 侯新烁, 2020, Stata数据处理:用-astile-快速创建分组, 连享会 No.324.
  • 卢家锐, 连玉君, 2020, Stata绘图:用-bytwoway-实现快速分组绘图, 连享会 No.357.
  • 孙晓艺, 2024, Stata绘图大礼包:27个常用的可视化范例及代码, 连享会 No.1372.
  • 温凯迪, 2023, Stata绘图:散点与分组密度函数图, 连享会 No.1208.
  • 胡艺泽, 2021, 倍分法:DID是否需要随机分组?, 连享会 No.567.
  • 胡雨霄, 2018, statsby: 不用循环语句的循环, 连享会 No.108.
  • 袁子晴, 2021, forest-森林图:分组回归系数可视化, 连享会 No.651.
  • 连享会, 2020, Stata:runby - 一切皆可分组计算!, 连享会 No.229.
  • 连玉君, 2020, Stata: 如何检验分组回归后的组间系数差异?, 连享会 No.19.
  • 马洪栋, 2024, Stata绘图:高级柱状图(一)-均值和置信区间-cibar-coefpl, 连享会 No.1379.

🍓 课程推荐:2024 机器学习与因果推断专题
主讲老师:司继春 (上海对外经贸大学) ;张宏亮(浙江大学)
课程时间:2024 年 11 月 9-10 日 ;16-17日
课程咨询:王老师 18903405450(微信)

尊敬的老师 / 亲爱的同学们:

连享会致力于不断优化和丰富课程内容,以确保每位学员都能获得最有价值的学习体验。为了更精准地满足您的学习需求,我们诚挚地邀请您参与到我们的课程规划中来。 请您在下面的问卷中,分享您 感兴趣的学习主题或您希望深入了解的知识领域 。您的每一条建议都是我们宝贵的资源,将直接影响到我们课程的改进和创新。 我们期待您的反馈,因为您的参与和支持是我们不断前进的动力。感谢您抽出宝贵时间,与我们共同塑造更加精彩的学习旅程!https://www.wjx.cn/vm/YgPfdsJ.aspx# 再次感谢大家宝贵的意见!

New! Stata 搜索神器:lianxhsongbl  GIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:
. ssc install lianxh
. ssc install songbl
👉  使用:
. lianxh DID 倍分法
. songbl all

🍏 关于我们

  • 连享会 ( www.lianxh.cn,推文列表) 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 直通车: 👉【百度一下: 连享会】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。


连享会
连玉君老师团队分享,主页:lianxh.cn。白话计量,代码实操;学术路上,与君同行。
 最新文章