使用向量化

算术运算符是一些特殊的内置函数,诸如 +、-、*、/、^ 和 %%。这些运算符不仅高效,
还是向量化的。
比如在 R 中完成一个 + 的实现:
add <- function(x, y) {
stopifnot(length(x) == length(y),
is.numeric(x), is.numeric(y))
z <- numeric(length(x))
for (i in seq_ _along(x)) {
z[[i]] <- x[[i]] + y[[i]]
}
z
}
接着,随机生成 x 和 y。add(x, y) 和 x + y 会返回相同的结果:
x <- rnorm(10000)
y <- rnorm(10000)
all.equal(add(x, y), x + y)
## [1] TRUE
下面的基准测试结果说明两者的性能差异是巨大的:
microbenchmark(add(x, y), x + y)
## Unit: microseconds
## expr min lq mean median
444 第 13 章 高性能计算
## add(x, y) 9815.495 10055.7045 11478.95003 10712.7710
## x + y 10.260 12.0345 17.31862 13.3995
## uq max neval cld
## 12598.366 18754.504 100 b
## 22.208 56.969 100 a
现在,假设需要计算前 n 个正整数的平方的倒数的和,用 for 循环可以轻松地实现这
个算法:
algo1_for <- function(n) {
res <- 0
for (i in seq_ _len(n)) {
res <- res + 1 /i ^ 2
}
res
}
此函数接收一个输入 n,迭代 n 次,逐次累加,最后返回结果。
一个更好的方法,就是直接使用向量化计算,避免使用 for 循环,就像 algo1_
vec( ) 的实现过程:
algo1_vec <- function(n) {
sum(1 / seq_ _len(n) ^ 2)
}
给定一个简单的输入,两个函数得到的结果相同:
algo1_ _for(10)
## [1] 1.549768
algo1_ _vec(10)
## [1] 1.549768
然而,它们的性能却大不相同:
microbenchmark(algo1_ _for(200), algo1_ _vec(200))
## Unit: microseconds
## expr min lq mean median uq
## algo1_for(200) 91.727 101.2285 104.26857 103.6445 105.632
## algo1_vec(200) 2.465 2.8015 3.51926 3.0355 3.211
## max neval cld
## 206.295 100 b
## 19.426 100 a
microbenchmark(algo1_ _for(1000), algo1_ _vec(1000))
## Unit: microseconds
## expr min lq mean median
## algo1_for(1000) 376.335 498.9320 516.63954 506.859
## algo1_vec(1000) 8.718 9.1175 9.82515 9.426
## uq max neval cld
## 519.2420 1823.502 100 b
## 9.8955 20.564 100 a
强烈推荐大家在写 R 代码时使用向量化。它不仅具有高性能,还会使你的代码更容易
理解。

posted @ 2019-02-11 14:31  NAVYSUMMER  阅读(120)  评论(0编辑  收藏  举报
交流群 编程书籍