HOWTO · R
在 R 中应用多参数函数
本教程演示了如何在 R 中应用带有多个参数的函数。
本页内容
要将需要多个参数的 R 函数应用于数据,可以在 apply() 或 lapply() 中把固定值放在函数之后传入;如果多个输入中的对应值要分别传给函数,则使用 mapply() 或 Map()。应根据输入形状以及所需结果是列表还是简化后的对象来选择函数。
向 apply 系列函数传入额外参数
apply(X, MARGIN, FUN, ...) 会将 FUN 应用于数组的各个切片。对于矩阵,MARGIN = 1 表示按行处理,MARGIN = 2 表示按列处理。放在 FUN 后面的参数会传给该函数,因此切片会变化,而这些参数可以保持固定。lapply(X, FUN, ...) 也采用相同的思路:它对列表中的每个元素调用一次 FUN,并始终返回列表。sapply() 采用相同的逐元素处理方式,但会尝试在可行时将列表结果简化为向量或矩阵;它本身并不一定更快。
运行以下示例:
本节中的代码以及显示的标签或输出仍为英文。
scores <- matrix(1:6, nrow = 2)
row_totals <- apply(scores, MARGIN = 1, FUN = function(row, scale, offset) {
sum(row * scale + offset)
}, scale = 2, offset = 1)
print(row_totals)
[1] 21 27
函数每次都会收到一行数据作为 row,而 scale 和 offset 则始终分别固定为 2 和 1。apply() 适用于数组;对数据框使用它时,各列可能会被强制转换为相同类型。如果需要保留列表元素及其类型,请使用 lapply() 或 Map()。
使用 mapply 处理并行参数
当每次函数调用都应接收多个输入中相同位置的值时,可以使用 mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE)。与 apply() 不同,它不会按矩阵边际选择数据切片。通过 MoreArgs 传入的值在每次调用中都保持固定;通过 ... 提供的值则会随调用而变化。默认情况下,mapply() 会尝试简化结果,方式与 sapply() 类似。
本节中的代码以及显示的标签或输出仍为英文。
add_with_tax <- function(price, tax, rate) price * (1 + rate) + tax
prices <- c(10, 20, 30)
fees <- c(1, 2, 3)
totals <- mapply(add_with_tax, prices, fees, MoreArgs = list(rate = 0.1))
print(totals)
[1] 12 24 36
这里,每个价格都会与同一位置的费用配对,而税率保持固定。当输入长度不同时,mapply() 会按照 R 的向量回收规则重复较短的输入;如果每个元素都必须一一对应,请使用长度相同的输入。如果更适合返回列表,可设置 SIMPLIFY = FALSE。
需要列表结果时使用 Map
Map(FUN, ...) 会将 FUN 应用于多个输入中位置对应的元素,并返回列表。它等同于禁用结果简化后的 mapply(),适合每次调用返回一个对象、且这些对象需要分别保留为列表元素的情况。
本节中的代码以及显示的标签或输出仍为英文。
combine <- function(values, multiplier) values * multiplier
parts <- list(first = 1:2, second = 3:4)
scaled <- Map(combine, parts, c(10, 100))
print(scaled)
$first
[1] 10 20
$second
[1] 300 400
每个列表元素都会与相同位置的乘数一起传给函数。即使这些元素可以合并为向量或矩阵,函数仍会返回列表。与 mapply() 一样,Map() 也会回收较短的输入;如果位置对应关系很重要,请检查各输入的长度。
选择合适的 apply 函数
- 对矩阵或其他数组的行或列进行处理,并传入固定的额外参数时,使用
apply()。 - 只有一个列表输入且结果必须始终保持为列表时,使用
lapply();如果简化后的结果有用,而且结果形状合适,可以使用sapply(),它会尝试简化结果。 - 当多个输入中位置对应的元素要分别成为每次函数调用的参数时,使用
mapply()。需要列表结果时,设置SIMPLIFY = FALSE。 - 对于相同的并行输入模式,如果默认需要列表结果,使用
Map()。
这四种情况下,先传入被应用函数本身所需的常规参数;如果为固定值命名能让作用更清楚,也应使用名称传入。对于 mapply() 和 Map(),请确认输入回收方式符合预期的配对关系。对于 apply(),请记住,数据框可能会在处理行或列之前被强制转换。选择函数时,这些行为差异比笼统的速度说法更有参考价值。