5

我已经学习 R 一段时间了,并且遇到了很多关于像我这样的编程类型来矢量化操作的建议。作为一名程序员,我对它为什么/如何更快感兴趣。一个例子:

n = 10^7
# populate with random nos
v=runif(n)
system.time({vv<-v*v; m<-mean(vv)}); m
system.time({for(i in 1:length(v)) { vv[i]<-v[i]*v[i] }; m<-mean(vv)}); m

这给了

   user  system elapsed 
   0.04    0.01    0.07 
[1] 0.3332091

   user  system elapsed 
  36.68    0.02   36.69 
[1] 0.3332091

要考虑的最明显的事情是我们正在运行本机代码,即从 C 或 C++ 编译的机器代码,而不是解释代码,正如两个示例之间用户时间的巨大差异所示(大约 3 个数量级)。但还有其他事情发生吗?例如,R 是否:

  • 巧妙的原生数据结构,例如存储稀疏向量或矩阵的巧妙方法,以便我们只在需要时进行乘法运算?

  • 惰性求值,例如矩阵乘法,在需要时才求值。

  • 并行处理。

  • 别的东西。

为了测试是否可能存在一些稀疏向量优化,我尝试用不同的向量内容做点积

# populate with random nos
v<-runif(n)
system.time({m<-v%*%v/n}); m
# populate with runs of 1 followed by 99 0s
v <-rep(rep(c(1,rep(0,99)),n/100))
system.time({m<-v%*%v/n}); m
# populate with 0s
v <-rep(0,n)
system.time({m<-v%*%v/n}); m

然而,时间没有显着差异(大约 0.09 过去)

(Matlab 的类似问题:为什么向量化代码在 MATLAB 中比 for 循环运行得更快?

4

3 回答 3

11

要考虑的最明显的事情是我们正在运行本机代码,即从 C 或 C++ 编译的机器代码,而不是解释代码

这是大部分。另一个重要的组件是,由于 R 代码在其设计范式中是函数式的,因此函数(尝试)没有副作用,这意味着在某些(但可能不是全部;R确实尝试对此有效)实例调用[<- 在 for 循环中导致必须复制整个对象。可能会变慢。

一个小的旁注:R 确实具有相当广泛的功能来有效地处理稀疏矩阵结构,但它们不是“默认”。

于 2013-06-03T18:07:35.100 回答
8

在这两个示例中,您都在运行解释代码和本机代码。不同之处在于,在第二个中,您在 R 级别执行循环,导致更多的函数调用都需要解释,然后调用 C 代码。在您的第一个示例中,循环发生在编译代码中,因此 R 的解释要少得多,R 代码调用要少得多,对编译代码的调用要少得多。

于 2013-06-03T18:31:17.283 回答
4

关于并行处理,开箱即用的 R 不做任何并行处理。当然有内置的parallel包,但你必须调整你的代码以使用例如mclapply使用并行处理。有一些选项可以让你的线性代数使用特殊版本并行计算blas,但这不是 R 中的标准使用,尽管让它工作似乎并不难。

于 2013-06-03T18:05:35.883 回答