Comparison of computation times

This document shows a comparison of computation time of TL-moments between different packages available, as well as between the different approaches built-in in this package.

This package offers the following computation methods (available via computation.method-attribute in TLMoments or TLMoment):

For a complete and thorough analysis of all these approaches and another speed comparison see Hosking & Balakrishnan (2015, A uniqueness result for L-estimators, with applications to L-moments, Statistical Methodology, 24, 69-80).

Besides our implementation, L-moments and/or TL-moments can be calculated using the packages

(all availabe at CRAN). The functions lmomco::lmoms, lmomco::TLmoms, and Lmoments::Lmoments return list objects with (T)L-moments and (T)L-moment-ratios and are therefore compared to our TLMoments; lmom::samlmu returns a vector of lambdas and is compared to TLMoment (which is a fast bare-bone function to compute TL-moments but is not suited to be transmitted to parameters or other functions of this package).

Calculation of L-moments

First we check, if all approaches give the same results (lmomco::lmoms is added as comparison).

n <- c(25, 50, 100, 200, 500, 1000, 10000, 50000)
sapply(n, function(nn) {
  x <- evd::rgev(nn)
  check <- lmomco::lmoms(x, 4)$lambdas
  sapply(c("direct", "pwm", "recursive"), function(comp) {
    isTRUE(all.equal(TLMoment(x, order = 1:4, computation.method = comp), check, check.attributes = FALSE))
  })
})
##           [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## direct    TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## pwm       TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## recursive TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

Now we compare the functions giving L-moments are L-moment-ratios simultaneously.

x <- evd::rgev(50)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, max.order = 4, computation.method = "direct"), 
  TLMoments(x, max.order = 4, computation.method = "pwm"), 
  TLMoments(x, max.order = 4, computation.method = "recursive"), 
  lmomco::lmoms(x, 4), 
  Lmoments::Lmoments(x, returnobject = TRUE)
)
## Unit: relative
##                                                           expr       min
##     TLMoments(x, max.order = 4, computation.method = "direct")  1.247122
##        TLMoments(x, max.order = 4, computation.method = "pwm")  1.130172
##  TLMoments(x, max.order = 4, computation.method = "recursive")  1.000000
##                                            lmomco::lmoms(x, 4) 16.859149
##                     Lmoments::Lmoments(x, returnobject = TRUE)  1.561048
##         lq      mean    median        uq       max neval
##   1.222758  1.221947  1.219421  1.196435 0.9779966   100
##   1.122484  1.077012  1.103262  1.070005 1.0088183   100
##   1.000000  1.000000  1.000000  1.000000 1.0000000   100
##  15.910520 15.051809 15.785747 15.164405 4.7700152   100
##   1.599098  1.533678  1.550068  1.549785 1.3017797   100
x <- evd::rgev(1000)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, max.order = 4, computation.method = "direct"), 
  TLMoments(x, max.order = 4, computation.method = "pwm"), 
  TLMoments(x, max.order = 4, computation.method = "recursive"), 
  lmomco::lmoms(x, 4), 
  Lmoments::Lmoments(x, returnobject = TRUE)
)
## Unit: relative
##                                                           expr        min
##     TLMoments(x, max.order = 4, computation.method = "direct")   3.321905
##        TLMoments(x, max.order = 4, computation.method = "pwm")   2.205974
##  TLMoments(x, max.order = 4, computation.method = "recursive")   1.000000
##                                            lmomco::lmoms(x, 4) 223.127604
##                     Lmoments::Lmoments(x, returnobject = TRUE)   1.526841
##          lq       mean     median         uq       max neval
##    3.187929   2.762694   3.128699   2.415718  1.060299   100
##    2.136949   1.942266   2.122409   1.747743  1.314967   100
##    1.000000   1.000000   1.000000   1.000000  1.000000   100
##  218.238503 184.517412 214.280436 153.821135 74.407946   100
##    1.559509   1.457766   1.681487   1.284248  1.050548   100

As we see, our implementation of the recursive approach is clearly the fastest. After this, the pwm approach is to be prefered over the direct approach. The implementation in lmomco is slow, compared to the others, especially for longer data vectors. Lmoments is constantly slower than the recursive approach of this package.

Comparison of functions that only return a vector of L-moments:

x <- evd::rgev(50)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoment(x, order = 1:4, computation.method = "direct"), 
  TLMoment(x, order = 1:4, computation.method = "pwm"), 
  TLMoment(x, order = 1:4, computation.method = "recursive"), 
  lmom::samlmu(x, 4), 
  Lmoments::Lmoments(x, returnobject = FALSE)
)
## Unit: relative
##                                                        expr       min
##     TLMoment(x, order = 1:4, computation.method = "direct")  2.570050
##        TLMoment(x, order = 1:4, computation.method = "pwm")  1.696397
##  TLMoment(x, order = 1:4, computation.method = "recursive")  1.000000
##                                          lmom::samlmu(x, 4)  1.129594
##                 Lmoments::Lmoments(x, returnobject = FALSE) 10.209451
##        lq      mean   median       uq        max neval
##  2.424083 1.3833811 2.365908 2.073667 0.04954821   100
##  1.641955 0.9742055 1.557987 1.486879 0.06139103   100
##  1.000000 1.0000000 1.000000 1.000000 1.00000000   100
##  1.305138 1.6472206 1.317427 1.239205 2.31513787   100
##  9.791030 5.3566622 8.852538 7.888361 0.21767345   100
x <- evd::rgev(1000)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoment(x, order = 1:4, computation.method = "direct"), 
  TLMoment(x, order = 1:4, computation.method = "pwm"), 
  TLMoment(x, order = 1:4, computation.method = "recursive"), 
  lmom::samlmu(x, 4), 
  Lmoments::Lmoments(x, returnobject = FALSE)
)
## Unit: relative
##                                                        expr       min
##     TLMoment(x, order = 1:4, computation.method = "direct") 16.219514
##        TLMoment(x, order = 1:4, computation.method = "pwm")  9.618965
##  TLMoment(x, order = 1:4, computation.method = "recursive")  2.498241
##                                          lmom::samlmu(x, 4)  1.000000
##                 Lmoments::Lmoments(x, returnobject = FALSE)  8.424014
##         lq      mean    median        uq       max neval
##  13.432317 13.202580 12.758043 12.711764 19.388344   100
##   7.991693  7.581657  7.613630  7.388048  4.918289   100
##   2.134150  2.060077  2.062312  2.022563  1.576473   100
##   1.000000  1.000000  1.000000  1.000000  1.000000   100
##   7.190713  8.730290  6.893787  6.939898 15.822386   100

For smaller data vectors our implementation is the fastest, but with longer data vectors lmom::samlmu excels.

Calculation of TL-moments

First we check, if all approaches give the same results (lmomco::Tlmoms is added as comparison)

n <- c(25, 50, 100, 150, 200, 500, 1000, 10000)
sapply(n, function(nn) {
  x <- evd::rgev(nn)
  check <- lmomco::TLmoms(x, 4, leftrim = 0, rightrim = 1)$lambdas
  sapply(c("direct", "pwm", "recursive", "recurrence"), function(comp) {
    isTRUE(all.equal(TLMoment(x, order = 1:4, rightrim = 1, computation.method = comp), check, check.attributes = FALSE))
  })
})
##            [,1] [,2] [,3] [,4]  [,5]  [,6]  [,7]  [,8]
## direct     TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE
## pwm        TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE
## recursive  TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
## recurrence TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE
sapply(n, function(nn) {
  x <- evd::rgev(nn)
  check <- lmomco::TLmoms(x, 4, leftrim = 2, rightrim = 4)$lambdas
  sapply(c("direct", "pwm", "recursive", "recurrence"), function(comp) {
    isTRUE(all.equal(TLMoment(x, order = 1:4, leftrim = 2, rightrim = 4, computation.method = comp), check, check.attributes = FALSE))
  })
})
##            [,1] [,2] [,3] [,4]  [,5]  [,6]  [,7]  [,8]
## direct     TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE
## pwm        TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE
## recursive  TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
## recurrence TRUE TRUE TRUE TRUE  TRUE  TRUE  TRUE  TRUE

The recursive approach fails when n exceeds 150. All other implementations give the same results.

x <- evd::rgev(50)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, max.order = 4, rightrim = 1, computation.method = "direct"), 
  TLMoments(x, max.order = 4, rightrim = 1, computation.method = "pwm"), 
  #TLMoments(x, max.order = 4, rightrim = 1, computation.method = "recursive"), 
  TLMoments(x, max.order = 4, rightrim = 1, computation.method = "recurrence"), 
  lmomco::TLmoms(x, 4, leftrim = 0, rightrim = 1)
)
## Unit: relative
##                                                                          expr
##      TLMoments(x, max.order = 4, rightrim = 1, computation.method = "direct")
##         TLMoments(x, max.order = 4, rightrim = 1, computation.method = "pwm")
##  TLMoments(x, max.order = 4, rightrim = 1, computation.method = "recurrence")
##                               lmomco::TLmoms(x, 4, leftrim = 0, rightrim = 1)
##        min        lq      mean    median        uq       max neval
##   2.668809  2.470516  2.053001  2.375475  1.834268 1.0513829   100
##   1.139518  1.091660  1.027709  1.068730  1.037583 0.4708621   100
##   1.000000  1.000000  1.000000  1.000000  1.000000 1.0000000   100
##  15.934675 15.572023 13.158572 14.979562 12.424656 5.0555835   100
x <- evd::rgev(1000)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, 4, rightrim = 1, computation.method = "direct"), 
  TLMoments(x, 4, rightrim = 1, computation.method = "pwm"), 
  #TLMoments(x, 4, rightrim = 1, computation.method = "recursive"), 
  TLMoments(x, 4, rightrim = 1, computation.method = "recurrence"), 
  lmomco::TLmoms(x, 4, leftrim = 0, rightrim = 1)
)
## Unit: relative
##                                                              expr
##      TLMoments(x, 4, rightrim = 1, computation.method = "direct")
##         TLMoments(x, 4, rightrim = 1, computation.method = "pwm")
##  TLMoments(x, 4, rightrim = 1, computation.method = "recurrence")
##                   lmomco::TLmoms(x, 4, leftrim = 0, rightrim = 1)
##        min         lq       mean     median         uq        max neval
##   19.67398  19.039676  17.206067  18.865113  15.840915  11.986615   100
##    2.31780   2.258958   2.156351   2.255527   2.104023   1.794551   100
##    1.00000   1.000000   1.000000   1.000000   1.000000   1.000000   100
##  175.03363 174.683893 160.128850 174.278530 145.368904 157.478230   100
x <- evd::rgev(50)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "direct"), 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "pwm"), 
  #TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recursive"), 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recurrence"), 
  lmomco::TLmoms(x, 4, leftrim = 2, rightrim = 4)
)
## Unit: relative
##                                                                                       expr
##      TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "direct")
##         TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "pwm")
##  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recurrence")
##                                            lmomco::TLmoms(x, 4, leftrim = 2, rightrim = 4)
##        min        lq      mean    median        uq       max neval
##   2.613737  2.525881  2.193864  2.427569  2.337747 0.5354382   100
##   1.238346  1.213057  1.092128  1.195855  1.192582 0.2911162   100
##   1.000000  1.000000  1.000000  1.000000  1.000000 1.0000000   100
##  14.233170 13.943644 13.282826 13.962493 14.849329 4.0831986   100
x <- evd::rgev(1000)
microbenchmark::microbenchmark(unit = "relative", 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "direct"), 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "pwm"), 
  #TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recursive"), 
  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recurrence"), 
  lmomco::TLmoms(x, 4, leftrim = 2, rightrim = 4)
)
## Unit: relative
##                                                                                       expr
##      TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "direct")
##         TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "pwm")
##  TLMoments(x, max.order = 4, leftrim = 2, rightrim = 4, computation.method = "recurrence")
##                                            lmomco::TLmoms(x, 4, leftrim = 2, rightrim = 4)
##         min         lq       mean     median         uq       max neval
##   18.976983  18.545630  16.008043  17.986779  14.332200  7.338456   100
##    3.658313   3.608269   3.290836   3.726356   2.991202  2.088247   100
##    1.000000   1.000000   1.000000   1.000000   1.000000  1.000000   100
##  167.100396 168.762797 148.164529 164.255487 130.182296 95.636781   100

In this calculations the recurrence approach clearly outperforms the other implementations. Calculation using probabilty-weighted moments is relatively fast, but using the direct calculation should be avoided, regarding calculation speed. This package's implementation is clearly faster than those in lmomco.

Conclusion

This results encourage to use the recursive approach for L-moments and the recurrence approach when calculating TL-moments. Therefore these are the defaults in this package, but the other computation methods are still available.