为什么对列表进行分类会减慢length()函数的速度?

时间:2016-12-27 18:56:17

标签: r performance

我刚刚注意到,通过向class属性添加附加标签(S3)或定义新的父类(S4)来对列表进行分类会大大降低基本lengths()操作的速度。

这表明在调用lengths()之前我应该​​总是取消“分类列表”。

任何人都可以

  1. 解释为什么会发生这种情况,和/或

  2. 建议一个更好的解决方案(或解释为什么这并不重要 因为差异只是绝对数字的微秒。)

  3. 可重复的代码:

    # create a list of 1,000 elements with variable letter lengths
    mylist <- list()
    length(mylist) <- 1000
    set.seed(99)
    mylist <- lapply(mylist, function(x) sample(LETTERS, size = sample(1:100, size = 1), 
                                                replace = TRUE))
    
    # create an S3 "classed" version
    mylist_S3classed <- mylist
    class(mylist_S3classed) <- c("myclass", "list")
    
    # create an S4 classed version
    setClass("mylist_S4class", contains = "list")
    mylist_S4classed <- new("mylist_S4class", mylist)
    
    # compare timings of lengths
    microbenchmark::microbenchmark(lengths(mylist),
                                   lengths(mylist_S3classed), 
                                   lengths(mylist_S4classed),
                                   unit = "relative")
    ## Unit: relative
    ##                      expr      min       lq     mean    median        uq       max neval
    ##           lengths(mylist)   1.0000   1.0000   1.0000   1.00000   1.00000   1.00000   100
    ## lengths(mylist_S3classed) 125.1433 119.3588 103.9747  91.90734  89.56034 291.97767   100
    ## lengths(mylist_S4classed) 162.4045 155.4870 119.0611 120.20908 111.95417  67.55309   100
    
    ## in absolute timings
    microbenchmark::microbenchmark(lengths(mylist),
                                   lengths(mylist_S3classed), 
                                   lengths(mylist_S4classed))
    ## Unit: microseconds
    ##                      expr      min        lq       mean    median       uq      max neval
    ##           lengths(mylist)    6.401    6.9475    9.66612    9.4620   10.577   29.237   100
    ## lengths(mylist_S3classed)  792.738  851.0895  911.97067  898.0955  939.558 1604.189   100
    ## lengths(mylist_S4classed) 1050.448 1104.7920 1293.63965 1173.4545 1229.485 6431.130   100
    

1 个答案:

答案 0 :(得分:5)

这个额外时间是R找到正确的length函数的时间。对于一个普通的旧列表,它非常容易和优化,它可能存储在对象中。得到它,归还它。

对于一个被分类的对象,无论是S3还是S4,R必须找到正确的length函数,因为length可以被定义为一种方法。所以R必须继续进行搜索,在你的情况下它会随处可见,直到它达到默认值。当它完成时,它花了那些毫秒。

除非你能告诉你未来的自己,你永远不会在这些对象上写length方法,因为你的代码会破坏...