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
):
direct
: Calculation as a weighted mean of the ordered data vector
pwm
: Calculation of probabilty-weighted moments and using the conversion to TL-moments
recursive
: An alternative recursive estimation of the weights of the direct approach
recurrence
: Estimating the L-moments first and using the recurrence property to derive TL-moments
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
lmomco
: L-moments and TL-moments
Lmoments
: L-moments and TL(1,1)-moments
lmom
: only L-moments
(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).
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.
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
.
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.