Skip to content

R - 函数

函数是执行特定任务的可重用代码块。在 R 语言中,函数是一等公民对象,这意味着你可以像使用任何其他变量一样使用它们。使用函数对于编写整洁、高效且易于维护的代码至关重要。

你可以使用 function 关键词创建 R 函数。基本语法如下:

function_name <- function(argument_1, argument_2, ...) {
# 要执行的代码(函数体)
return_value # 最后求值的表达式会自动返回
}
  • 函数名称:你用来调用函数的名称(例如,function_name)。它作为对象存储在 R 环境中。
  • 参数(Arguments):传递给函数的数据的占位符。它们可以有默认值,从而变为可选。
  • 函数体(Function Body):定义函数执行操作的一系列 R 语句。
  • 返回值(Return Value):函数的结果。在 R 中,函数内部最后求值的表达式的值会自动返回。你也可以显式使用 return()。

一个纯函数是指,对于相同的输入,它总是返回相同的输出,并且没有可观察的副作用(例如打印到控制台或修改全局变量)。尽可能编写纯函数是一种最佳实践,因为它们更易于测试和理解。

让我们重构原始示例以遵循此原则。我们的函数将返回一个平方数的向量,而不是在循环内部打印平方值(这是一个副作用)。

# 一个用户定义函数,用于计算数字序列的平方。
# 这是一个“纯”函数:它返回一个值且没有副作用。
calculate_squares <- function(n) {
# 输入验证:检查 n 是否是单个正整数
if (!is.numeric(n) || length(n) != 1 || n < 1) {
stop("Argument 'n' must be a single positive integer.")
}
# 'sapply' 函数是 R 中对向量应用函数的一种更符合习惯的方式
sapply(1:n, function(x) x^2)
}
# 调用函数并存储结果
squared_numbers <- calculate_squares(6)
# 现在,打印结果(副作用在函数外部)
print(squared_numbers)

当我们执行上述代码时,它会产生一个整洁的向量作为输出:

[1] 1 4 9 16 25 36

你可以通过参数的位置或显式命名它们来向函数提供参数。命名参数通常更清晰且不易出错。

# 一个具有多个参数的简单函数
calculate_result <- function(a, b, c) {
result <- a * b + c
return(result)
}
# 按位置调用 (5*3 + 11)
print(calculate_result(5, 3, 11))
# 按名称调用(顺序无关紧要)
print(calculate_result(c = 3, a = 11, b = 5))

这会产生以下结果:

[1] 26
[1] 58

你可以为参数提供默认值,使它们在函数被调用时成为可选。

# 一个带默认参数的函数
create_greeting <- function(name, greeting = "Hello") {
paste(greeting, name, sep = ", ")
}
# 调用函数,使用默认问候语
print(create_greeting("Alice"))
# 调用函数,覆盖默认值
print(create_greeting("Bob", greeting = "Goodbye"))

这会产生以下结果:

[1] "Hello, Alice"
[1] "Goodbye, Bob"

管道操作符 %>%(来自 magrittr 包,或 R 4.1+ 中原生的 |>)是一个强大的工具,可以提高代码的可读性。它将左侧表达式的结果作为第一个参数传递给右侧的函数。

library(magrittr) # 或 library(dplyr)
# 不使用管道
print(round(mean(1:10)))
# 使用管道:读起来像一句话“取 1:10,然后求均值,然后四舍五入,然后打印”
1:10 %>%
mean() %>%
round() %>%
print()

两个表达式产生相同的结果,但管道版本对于复杂的操作链通常更容易理解。

[1] 6
[1] 6

R 是一种非常适合函数式编程的语言。tidyverse 中的 purrr 包提供了一套完整且一致的工具,用于处理函数和向量。这是掌握基础知识后的绝佳下一步。例如,purrr::map() 是 loops 或 sapply() 的强大替代方案。