学习强大的方法,超越if-else语句,提高你的R代码水平
没有条件语句,编程是不可能的。
条件语句基于真/假条件执行代码。它们是编程的基本部分,尤其是在R中。无论你是用R进行数据分析,机器学习,软件开发还是其他什么,条件语句都有无限的用途。
但是,大多数R初学者并不知道有许多编写条件语句的方法。许多人学习了基本if-else语句并停止了。但是,通常有更整洁,更高效的编写条件语句的方法。高级R程序员知道每种技术及何时使用它们。那么,你如何学会做到这一点呢?
在本文中,我们将介绍四种在R中编写条件语句的不同方法。我们还将介绍每种技术的优点和局限性,以及何时使用每种方法。
如何在R中编写if-else语句
在R中编写条件语句的最简单方法是使用if
和else
关键字。如果你已经了解另一种编程语言,那么这将是最熟悉的技术,通常是新的R用户首先学习的技术。
R中的标准if语句如下:
if (condition) { # Code to execute}
这里,condition
是一个逻辑表达式,返回TRUE
或FALSE
。如果条件返回TRUE
,则执行花括号内的任何代码。如果返回FALSE
,则不执行花括号内的代码,并且R移动到脚本中的下一行代码。
为了了解这在实践中是如何工作的,我们可以看下面的例子。
age <- 25if (age >= 18) { age_group <- "adult"}
在这里,我们有一个包含年龄的变量。然后,if语句评估age
的值是否大于或等于18。在这种情况下为真,因此变量age_group
的值为"adult"
。
这是检查简单条件并在条件为真时执行某些操作的简单方法。但是,如果我们希望语句在条件为假时运行一些代码怎么办?
如果else语句是基本if语句的扩展。为了理解它们,我们可以在之前的例子中添加内容。
if (age >= 18) { age_group <- "adult"} else { age_group <- "child"}
这段代码的工作方式与上一个例子相同,只有一个例外。当条件为FALSE
时,else之后花括号内的代码将被执行。这意味着如果age
大于或等于18,则将为age_group
分配"adult"
的值。如果不是,则将age_group
设置为"child"
。
if-else语句是控制R脚本中代码的简单方法。它们易于理解,可以扩展以满足许多条件,并且可以执行许多行的复杂代码。
但是,if-else语句可能占用大量空间。对于像上面的简单表达式,有其他方法可以使用相同的操作而不使用五行代码。
实际上,可以使用一行代码编写if-else语句。
R中的内联条件语句
内联条件语句是一种将“if-else”逻辑以单行代码的简洁方式表示的方法。有几种编写它们的方法。
行内 if else 语句
首先,我们可以使用 if
和 else
关键字编写一个简单的行内语句。它的形式如下:
age_group <- if (age >= 18) "adult" else "child"
这个语句的工作方式与前一个例子相同。唯一的区别是,现在我们已经压缩了措辞以适应一行。如果条件是 TRUE
,则 age_group
的值会更新为 else
关键字之前的任何值 —— 在这种情况下,是 “adult”
。如果是 FALSE
,age_group
将被分配任何在 else
之后的值。
这里的重大区别在于我们现在将整个条件语句的结果分配给变量 age_group
。这改进了标准的 if-else 示例中的重复措辞,在那里我们不得不写这个分配两次。
Base-R ifelse 函数
如果你愿意,你可以使用 ifelse
函数。下面的代码使用此函数执行与前面示例相同的逻辑。
age_group <- ifelse(age >= 18, "adult", "child")
ifelse
函数接受三个参数。首先是条件,然后是条件为真时返回的值,以及条件为假时返回的值。
这是编写短条件语句的一种清晰、直接的方法。它还有另一个优点;它是向量化的。
让您的 R 代码快 10 倍:向量化在 3 分钟内解释
告别缓慢、混乱的循环
towardsdatascience.com
向量化是 R 中的一个重要概念。如果一个函数是向量化的,它会自动应用于多个值,而不仅仅是一个值。为了看一个使用 ifelse
函数的例子,让我们给变量 age
分配更多的值,并再次运行代码。
age <- c(16, 45, 23, 82)age_group <- ifelse(age >= 18, "adult", "child")# 返回 "child" "adult" "adult" "adult"
ifelse
函数自动评估 age
中的所有值,返回相应输出的序列。这使得 ifelse
成为一种无需慢速、混乱的循环评估许多简单条件的清晰方法。
R 中的条件索引
虽然 ifelse
可以轻松地评估许多输入,但还有其他方法可以实现这一点。
索引允许 R 程序员访问包含许多值的数据结构的特定部分。例如,如果我们想要获取向量 age
中的第三个元素,我们可以在方括号内使用 3 索引 age
:
age <- c(16, 45, 23, 82)age# 返回 16、45、23、82age[3]# 返回 23
通常使用数字来索引具有特定位置的值,就像上面的代码一样。但是,许多初学者 R 程序员不知道,当索引时也可以使用逻辑条件。这开启了各种可能性。
让我们创建一些示例数据,以说明其中一些选项。这包括一些关于用户的信息,例如年龄,与之前的示例相同。但是,每个用户的信息不是存储在向量中,而是以行方式存储在 tibble 中。如果在专业环境中处理用户数据,这是您可能会看到的数据结构,因此了解如何将条件逻辑应用于它是有用的。
set.seed(123)user_data <- tibble( user_id = 1:10, age = floor(runif(10, min = 13, max = 35)), region = sample(c("UK", "USA", "EU"), 10, replace = TRUE))

Tibbles 和数据框由向量组成,这意味着我们可以以相同的方式对它们进行索引。这使我们能够做各种各样的事情。
基于条件提取列中的值
这里是一些代码,提取user_id
列中任何用户年龄小于18岁的值。
user_data$user_id[user_data$age < 18]# 返回6
基于条件替换列中的值
这是如何将区域列中所有“UK”行重新编码为“EU”的方法。
user_data$region[user_data$region == "UK"] <- "EU"

使用条件索引过滤数据集
我们甚至可以使用条件子集来过滤整个数据集。这是一种过滤区域为“USA”的所有行的方法。请注意,在此逻辑条件之后,我们包括一个逗号,告诉 R 我们正在按行索引。如果我们想按列过滤,可以在逗号后添加一个条件。
user_data[user_data$region == "USA",]

这些只是 R 中条件索引的几个应用。如果您需要对数据进行快速的条件操作,那么很有可能使用此方法有一行解决方案。
Tidyverse 的 case_when 函数
case_when
函数来自 tidyverse 包系列。这是另一种在许多值集上应用条件语句的方法,当然在处理数据集时非常有用。
我们可以使用上一个示例中的数据来展示如何基于条件语句使用 case_when
创建一个新列。
user_data %>% mutate(drinking_age = case_when(region == "USA" & age >= 21 ~ TRUE, region == "EU" & age >= 18 ~ TRUE, .default = FALSE))

此代码根据用户的年龄和位置确定我们的网站用户是否可以合法饮酒。这里,每个条件在 case_when
语句中的不同行上。如果条件成立,我们可以在波浪线(~)符号之后返回一个值——在这种情况下为 TRUE
。如果没有一个条件被满足,则返回的值由 .default
设置指定。所有值都存储在一个新列 drinking_age
中。
如果这看起来有点陌生,下面是相应的 if else 语句:
if (region == "USA" & age >= 21) { drinking_age <- TRUE} else if (region == "EU" & age >= 18) { drinking_age <- TRUE} else { drinking_age <- FALSE}
与上面的代码相比,可以看出case_when
提供了另一种比if-else语句更简洁、同样强大的条件语句实现方式。对于基于复杂逻辑或多个条件创建新列,这是我的首选。对于tidyverse用户,这是必须采用的功能。
何时使用不同种类的条件语句
我介绍的方法只有在应用到自己的代码中时才真正发挥作用。只有通过尝试新的方法并熟悉它们,才能获得它们的全部好处并实现R编程自如。
那么,何时应该使用每种类型的条件语句呢?
和编程中的任何方法选择一样,没有一个直接的答案。尽管如此,这里有一些我用来帮助选择不同的条件语句写法的粗略指南。
- 如果我正在解决需要在某些条件下执行大量复杂的多行代码的问题,我通常更喜欢使用if-else语句。在这些情况下,使用其他方法通常会变得混乱和难以维护。
- 对于条件更简单、代码块更短的问题,我喜欢使用内联if-else语句。没有必要让简单的解决方案变得比必要的长!
- 如果使用数据集或基于条件创建列,则使用
case_when
。它与我使用的其他tidyverse函数配合得很好,易于调试和维护。 - 如果我正在使用数据集并且不想加载额外的软件包,我将使用条件索引。它不需要任何额外的依赖关系,而且通常运行速度很快。
我的建议?尝试使用每种技术,看看哪种最适合您。至少,您可能会学到一种新的使代码更好的方法。
因此,如果您喜欢这篇文章,为什么不分享您最喜欢的条件语句呢?否则……感谢您一直阅读到最后!