R语言是以向量化编程而闻名的。因此R的for循环相比于向量化操作而言有时候会较慢。
R – for loop
1 | for (variable in vector) { |
有两种方法可以提前终止for
循环
next
退出当前迭代break
退出整个for
循环
1 | for (i in 1:10) { |
1 | [1] 3 |
下面用以下的例子实测R语言中的循环的效率。
- 使用 for 循环取一千万个数值的绝对值,并使用
system.time
函数测量函数运行的时间。
1 | #生成一个包含正数和负数的长向量,总共有一千万个数值 |
- 再使用R中向量化的方式进行上述操作
1 | abs_set <- function(x){ |
在使用了R中向量化编程的方式(逻辑判断、取子集、元素方式执行)后,速度提升了大约30倍。
- 最后,我们看看R中自带的取绝对值函数
abs
有多快R中的自带函数几乎是1
2
3> system.time(abs(long))
用户 系统 流逝
0.02 0.02 0.03for
循环速度运行的300倍!这是由于R中很多basic的函数都是经过多次优化与调试的,所以在可能的情况下,应该尽量避免对其自带函数的修改。
for循环常见的使用错误
通过循环赋值时,要预先生成变量
如果我们需要通过for
循环赋值,我们需要预先生成好容器变量,并设置变量相应属性,这将会提升for
循环的效率
假设我们需要在1000个不同均值的正态分布中随机抽取1000个数,并存储到列表中:
1 | means <- c(1:1000) |
可以发现使用vector()
预先设置好容器的长度将会提升for
循环赋值的速度约2.3倍
使用seq_along()
迭代
上面我们使用1:length(mean)
对mean
向量进行迭代,但这种方法在向量为空时将会报错。
1 | means <- c() |
因此,尽可能使用seq_along()
对向量进行迭代。seq_along()
返回与输入向量等长的序列
1 | > seq_along(11:20) |
所以,如果向量为空也不用担心报错
1 | seq_along(means) |
S3向量的循环
有时候,对S3向量进行迭代时,我们也可能碰到以下问题
1 | xs <- as.Date(c("2020-01-01", "2010-01-01")) |
这是由于循环解除了变量的属性,这个时候使用双中括号[[
可以解决
1 | for (i in seq_along(xs)) { |
总而言之,for
循环会比较符合我们的直观思维,但在R中向量化编程的方式会提高我们处理任务的效率。当然,有时候向量化编程也会起到反作用,切记具体情况具体分析,而不是死磕一种方法。
Ref:
Advanced R: https://adv-r.hadley.nz/control-flow.html
完。