作为标题,我想知道如何在 R 中定义矢量化函数。
- 只是在函数中使用循环吗?
- 这种方法有效吗?
- 什么是最佳做法?
R 级别的循环未矢量化。R 循环将为向量的每个元素调用相同的 R 代码,这将是低效的。向量化函数通常是指那些采用向量并以有效方式对整个向量进行操作的函数。最终,这将涉及一些 for of 循环,但由于该循环是用 C 等低级语言执行的,因此它可以非常高效并针对特定任务进行定制。
考虑这个愚蠢的函数来成对添加两个向量的元素
sillyplus <- function(x, y) {
out <- numeric(length = length(x))
for(i in seq_along(x)) {
out[i] <- x[i] + y[i]
}
out
}
它给出了正确的结果
R> sillyplus(1:10, 1:10)
[1] 2 4 6 8 10 12 14 16 18 20
并且是向量化的,因为它可以一次对整个向量进行操作,但它不是我上面描述的意义上的向量化,因为它非常低效。+
在 R 中的 C 级别向量化,所以我们真的只需要1:10 + 1:10
,而不是 R 中的显式循环。
编写向量化函数的常用方法是使用已经向量化的现有 R 函数。如果您想从头开始,并且您想要对函数执行的操作在 R 中不作为矢量化函数存在(奇怪,但可能),那么您将需要亲自动手并将函数的内容写入C 并在 R 中准备一个小包装器,以使用您希望它处理的数据向量调用您编写的 C 函数。有一些方法可以Vectorize()
为未矢量化的 R 函数伪造矢量化。
C 不是这里唯一的选择,FORTRAN 和 C++ 一样是可能的,并且感谢 Dirk Eddelbuettel 和 Romain Francois,后者现在使用rcpp包更容易实现。
向量化函数将返回与其参数之一长度相同的向量。通常,可以通过使用诸如“+”之类的内置函数的组合来获得这样的函数,cos
或者exp
也可以使用向量化的函数。
vecexpcos <- function(x) exp(cos(x))
vecexpcos( (1:10)*pi )
> vecexpcos( (1:10)*pi )
# [1] 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818 0.3678794 2.7182818
如果您需要使用非矢量化函数,例如sum
,您可能需要调用mapply
或Vectorize
以获得所需的行为。
派对迟到了,但我认为这个问题仍然高度相关,并且最近有一些新方法受到欢迎。因此,还有另一种使用方法对 R 中的函数进行矢量化的tidyverse
方法。
首先,定义一些数据:
x <- c(1,2,3)
y <- c(1,2,4)
现在,假设,我们想对这两个向量执行一些元素计算,使得f(x,y)
.
例如,计算 x 和 y 的每个(一对)元素的总和应该得到:2,4,7。
让我们使用map2_dbl
from purrr
(来自 tidyverse 生态系统的一个包):
x <- c(1,2,3)
y <- c(1,2,4)
library(tidyverse)
map2_dbl(.x = x,
.y = y,
.f = sum)
#> [1] 2 4 7
可以看出,从 x 和 y 的每对元素计算总和的意义上来说,结果是矢量化的。
总之,map()
至少在某些情况下,使用及其变体是向量化函数的便捷方式。