为什么seq(x)比1慢得多:length(x)?

Ric*_*ven 22 r

我最近回答了一个关于for循环的问题.在测试我的代码速度后,我注意到在循环中使用seq()相反的速度会大大降低速度. :for

看看这个非常简单的例子.f1()和之间的唯一区别f2()for循环序列的变化,但f1()速度是其两倍f2().

f1 <- function() {
    x <- 1:5; y <- numeric(length(x))
    for(i in 1:length(x)) y[i] <- x[i]^2
    y
}

f2 <- function() {
    x <- 1:5; y <- numeric(length(x))
    for(i in seq(x)) y[i] <- x[i]^2
    y
}

library(microbenchmark)
microbenchmark(f1(), f2())
# Unit: microseconds
#  expr    min      lq  median     uq    max neval
#  f1() 10.529 11.5415 12.1465 12.617 33.893   100
#  f2() 25.052 25.5905 26.0385 28.759 78.553   100
Run Code Online (Sandbox Code Playgroud)

为什么循环中的seq(x)速度要慢for得多1:length(x)

dar*_*sco 24

seq是一种通用的S3方法,所以可能有一些时间丢失了调度. seq.default几乎是100行!

你可能已经知道了seq_along,它.Primitive直接调用了一个并且比1:length(x)我在长循环中找到的最好的方法更好:

f3 <- function(){
      x <- 1:5; y <- numeric(length(x))
      for(i in seq_along(x)) y[i] <- x[i]^2
      y
  }
>  microbenchmark(f1(), f3())
Unit: microseconds
 expr    min     lq median     uq    max neval
 f1() 27.095 27.916 28.327 29.148 89.495   100
 f3() 26.684 27.505 27.916 28.327 36.538   100
Run Code Online (Sandbox Code Playgroud)


ags*_*udy 9

使用seq_len您几乎与:运营商同时:

f3 <- function(){
  x <- 1:5; y <- numeric(length(x))
  for(i in seq_len(length(x))) y[i] <- x[i]^2
  y
}

library(microbenchmark)
microbenchmark(f1(), f2(),f3())

Unit: microseconds
 expr    min      lq  median     uq    max neval
 f1()  9.988 10.6855 10.9650 11.245 50.704   100
 f2() 23.257 23.7465 24.0605 24.445 88.140   100
 f3() 10.127 10.5460 10.7555 11.175 18.857   100
Run Code Online (Sandbox Code Playgroud)

在内部seq被调用之前做许多验证:seq_len.