R数据处理-多条件判断:ifelse() 和 case_when()

文摘   2024-11-04 22:00   中国  

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

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

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

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

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

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

1. 简介

在 R 中,数据处理和数据清洗是常见任务之一,而 case_when() 函数提供了一种优雅的方式来执行条件判断并返回不同的结果。相比传统的 if...else... 语句,case_when() 的语法简洁明了,非常适合在 tidyverse 的管道操作风格下使用。

本文将详细介绍 case_when() 的语法、与 if...else... 的对比,以及使用示例。

2. case_when() 的语法规则

case_when()dplyr 包提供的一个函数,用于多条件判断。与传统的 if...else... 语句相比,case_when() 能够更加直观地处理多种情形。在处理数据时,经常需要根据某些条件给出不同的结果,例如根据成绩分类、根据年龄分组等,case_when() 就非常适合这种场景。

case_when() 的基本语法如下:

case_when(
  condition1 ~ result1,
  condition2 ~ result2,
  condition3 ~ result3,
  TRUE ~ default_result
)
  • condition:逻辑条件,可以是任何返回 TRUE/FALSE 的表达式;
  • result:条件成立时返回的值,可以是任意类型的数据;
  • TRUE:用作默认选项。当所有条件都不满足时,将返回该结果。类似于 else 的作用。

需要特别注意的是上述代码的格式规范:

  • case_when() 中,每一个「条件 → 结果对」都可以视为一个输入项 (argument),因此,多个「条件 → 结果对」之间需要用逗号分隔;
  • 每个「条件 → 结果对」必须使用 ~ 符号来连接「条件」和与之对应的「结果」。

3. 传统做法:if...else... 表达式和 ifelse() 函数

为帮助理解 case_when() 的语法逻辑,我们来看一下传统的 if...else... 表达式,以及 ifelse() 函数如何实现相同的逻辑。

if...else... 语法

if...else... 的写法如下:

if (condition1) {
  result1
else if (condition2) {
  result2
else if (condition3) {
  result3
else {
  default_result
}

ifelse() 函数

如果使用 ifelse() 函数,则语法如下:

ifelse(
  condition1, result1,
  ifelse(
    condition2, result2,
    ifelse(
      condition3, result3,
      default_result
    )
  )
)

在此伪代码结构中:

  • condition1:第一个逻辑条件,若为 TRUE,则返回 result1
  • condition2condition3:若 condition1 不满足,则进入下一层 ifelse() 判断,依次评估 condition2condition3,当条件满足时返回对应结果;
  • default_result:当所有条件都不满足时返回的默认值。

对比

细心的读者可能已经发现,传统的 if...else... 表达式最容易理解,但编写代码时会稍显繁琐;而 ifelse() 函数则把条件和相应的结果放在了同一行,这样读起来比较自然。相比之下,case_when() 则在 ifelse() 的基础上更进了一步,直接采用 列表方式 来罗列条件 (并基于条件出现的先后顺序来确定它们之间的递进关系),一目了然。

4. 实操范例

假设我们有一份学生的成绩单,包含学生姓名 name 和成绩 score。我们想基于如下标准定义一个新变量 grade (取值为:优秀,良好,及格,不及格):

  • 成绩 ≥ 90:优秀
  • 80 ≤ 成绩 < 90:良好
  • 60 ≤ 成绩 < 80:及格
  • 成绩 < 60:不及格

首先,我们创建一个示例数据框:

library(dplyr)

data <- tibble(
  name  = c("Alice""Bob""Charlie""Diana""Eve"),
  score = c(8892746553)
)

最终,我们想要得到的结果是:

namescoregrade
Alice88良好
Bob92优秀
Charlie74及格
Diana65及格
Eve53不及格

接下来,我们分别使用 if...else...ifelse()case_when() 来生成 grade 变量,借此帮助大家理解三种方法的差别,尤其是向量化操作的优势。

4.1 if...else... 实现

在 R 中,if...else... 语法本身不支持直接对向量操作,因此,如果用 if...else... 实现条件判断,我们通常会用 for 循环来遍历每个元素,或使用 sapply() 函数来简化操作。下面分别展示这两种实现方式。

4.1.1 使用循环语句的方法

首先,通过 for 循环逐一判断 score 中每个元素的等级,并将结果存储在 grade 向量中:

# 创建一个空向量,用于存储 grade
grade <- character(length(data$score))

# 使用 for 循环和 if...else...
for (i in seq_along(data$score)) {
  if (data$score[i] >= 90) {
    grade[i] <- "优秀"
  } else if (data$score[i] >= 80) {
    grade[i] <- "良好"
  } else if (data$score[i] >= 60) {
    grade[i] <- "及格"
  } else {
    grade[i] <- "不及格"
  }
}

# 将结果合并到数据框中
data <- data %>%
  mutate(grade = grade)

# 查看结果
data

在这种实现中,for 循环逐一检查 score 中的每个值,并根据条件给出对应的 grade,但这种方法在数据量大时效率较低,代码也相对复杂。

4.1.2 使用 sapply() 实现向量化操作

为了避免显式编写循环,可以使用 sapply() 来简化代码。sapply() 可以对向量 score 中的每个元素应用 if...else... 判断,并将返回的结果存储在 grade 列中:

# 使用 sapply() 简化 if...else... 判断
data <- data %>%
  mutate(grade = sapply(score, function(x) {
    if (x >= 90) {
      "优秀"
    } else if (x >= 80) {
      "良好"
    } else if (x >= 60) {
      "及格"
    } else {
      "不及格"
    }
  }))

# 查看结果
data

# A tibble: 5 × 3
  name    score grade 
  <chr>   <dbl> <chr> 
1 Alice      88 良好  
2 Bob        92 优秀  
3 Charlie    74 及格  
4 Diana      65 及格  
5 Eve        53 不及格

在这里,sapply() 对每个 score 元素执行 if...else... 判断并返回一个向量 grade,实现了向量化处理,使代码更加简洁。

4.2 ifelse() 实现

ifelse() 是 R 中专门用于向量化条件判断的函数。它能够直接对向量中的每个元素进行条件判断,无需显式循环。我们可以使用嵌套的 ifelse() 来实现与 case_when() 类似的逻辑。

# 使用嵌套的 ifelse()
data <- data %>%
  mutate(grade = ifelse(score >= 90"优秀",
                        ifelse(score >= 80"良好",
                               ifelse(score >= 60"及格""不及格"))))

# 查看结果
data

ifelse() 中,每个条件语句都是向量化的,适合直接处理向量数据,代码更简洁且性能更高。

4.3 case_when() 实现

case_when()dplyr 包中的一个函数,提供了更简洁的多条件判断结构。它也支持向量化操作,并且在语法上更加清晰,非常适合用于多条件判断场景,尤其是在 dplyr 的管道操作中。

# 使用 case_when()
data <- data %>%
  mutate(grade = case_when(
    score >= 90 ~ "优秀",
    score >= 80 ~ "良好",
    score >= 60 ~ "及格",
    TRUE ~ "不及格"
  ))

# 查看结果
data

case_when() 的写法清晰明了,条件和结果的逻辑分离开来,便于阅读,适合多条件判断的情况。

5. 三种方法的对比

上述介绍的三种方法的优劣总结如下:

方法是否支持向量化代码简洁性推荐使用场景
if...else... +
for 循环
较复杂条件较少或代码教学
sapply() +  
if...else...
部分支持较简洁简单数据的向量化处理
ifelse()简洁基础的条件判断
case_when()简洁清晰多条件判断,嵌入 dplyr 管道

可见,后两种方法——ifelse()case_when() 都支持向量化操作,能直接处理整个向量的数据,无需手动编写循环,因此更为简洁且运行效率更高。特别是 case_when(),它的语法更清晰,适合条件较多的情境。

整体而言,case_when() 是编写整洁、高效代码的绝佳选择。

6. 扩展阅读

以下是一些关于 case_when() 函数及其在 R 数据处理中的应用的参考资料,供进一步学习:

  1. R for Data Science

  • 作者:Hadley Wickham & Garrett Grolemund
  • 内容:此书第 5 章介绍 dplyr 包中的函数,包括 case_when() 的应用。
  • 在线阅读:R for Data Science (R4DS)
  • PDF:R for Data Science
  • GitHub 仓库:https://github.com/hadley/r4ds
  • dplyr vignettes

    • 内容:dplyr 官方手册中有对 case_when() 的详细介绍及示例。
    • 在线阅读:dplyr Vignettes
  • CRAN Documentation: dplyr package

    • 内容:详细的函数使用文档,包含 case_when() 语法和示例。
    • 在线文档:dplyr Documentation
  • Advanced R

    • 作者:Hadley Wickham
    • 内容:此书介绍了 R 中函数式编程思想,为理解 case_when() 等函数的灵活应用奠定了理论基础。
    • 在线阅读:Advanced R
    • GitHub 仓库:https://github.com/hadley/adv-r
  • Tidyverse Blog

    • 内容:tidyverse 团队发布的文章,包括 dplyr 和 case_when() 的实际应用案例。
    • 在线阅读:Tidyverse Blog
  • Hands-On Programming with R

    • 作者:Garrett Grolemund
    • 内容:本书对 R 编程的介绍适合初学者,包含条件判断的基础内容,可帮助理解 case_when()ifelse() 的区别。
    • 在线阅读:Hands-On Programming with R

    7. 相关推文

    Note:产生如下推文列表的 Stata 命令为:
    lianxh R语言:Rstudio 安装并使用, md0 nocat
    安装最新版 lianxh 命令:
    ssc install lianxh, replace

    • 刘晓飞, 2024, R语言:基本的数据处理和统计分析实例, 连享会 No.1414.
    • 刘潍嘉, 2023, R语言:如何理解F检验, 连享会 No.1273.
    • 吴小齐, 2023, R语言:L2 Boosting 在经济学中的应用, 连享会 No.1288.
    • 吴小齐, 2023, R语言:将tikz图片转换为PNG, 连享会 No.1289.
    • 李明来, 2021, R和RStudio安装教程, 连享会 No.773.
    • 罗银燕, 2023, 如何在 R 中安装并使用 chatgpt 包?, 连享会 No.1171.
    • 范思妤, 2024, R/RStudio下载安装指南, 连享会 No.1333.
    • 连玉君, 2024, RStudio常用的快捷键一览, 连享会 No.1481.
    • 邱一崎, 2024, R语言:因果推断中的混淆变量、交互项和线性回归, 连享会 No.1369.
    • 闫钊鹏, 2023, R语言:gtExtras包-绘制漂亮的表格和图形, 连享会 No.1311.
    • 雷诺, 2023, R语言:拆解因果推断中的后门法则, 连享会 No.1323.

    🍓 课程推荐: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。白话计量,代码实操;学术路上,与君同行。
     最新文章