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

时间:2014-06-13 23:26:56

标签: 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

为什么seq(x) for循环中的1:length(x)比{{1}}慢得多?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

内部seq在调用:seq_len之前会进行多次验证。

答案 2 :(得分:1)

更慢的具体原因:

seq(x)会致电seq.default *,seq.default来电1L:x !!

来自seq.default

if ((One <- nargs() == 1L) && !missing(from)) {
    lf <- length(from)
    return(if (mode(from) == "numeric" && lf == 1L) {
        #checks validity -- more slow-down
        if (!is.finite(from)) stop("'from' cannot be NA, NaN or infinite")
        #boom! under the hood, seq.default is doing 1:N
        1L:from
    #looks like it defaults to seq_along if length(from) > 1?
    } else if (lf) 1L:lf else integer())
}

*当然,除非xDatePOSIXt,否则您加载了另一个具有seq方法的库...