The previous tutorial introduced S3 and piping into distr6, allowing different approaches to calling R6 methods. In this tutorial we take a look at a big feature of distr6, decorators.
Note: Decorators in distr6 are still maturing, this means the API is still subject to minor changes and the internal computations may be improved, therefore we are aware performance may be sub-optimal.
In object-oriented programming it is common to discuss ‘Design
Patterns’ as specific methods used to solve coding problems, decorators
are one of these ‘patterns’. For full definitions and details about
design patterns, we refer the reader to the seminal Design Patterns
textbook (Gamma et al. 1994). Briefly, the
decorator design pattern is used to add functionality to an object. For
example, say we have a class that only has a print
method
and a decorator for summary
methods. Then the user can
either use the object by itself with the print
method only
or optionally you can ‘decorate’ the object and thereby use the
summary
method. This is perhaps confusing in the abstract,
so lets work through an example in distr6. We will go through a quick
example and then return to which decorators are available and how they
are used in distr6:
N <- Normal$new()
N$survival(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(N, "ExoticStatistics")
#> Normal is now decorated with ExoticStatistics
#> Norm(mean = 0, var = 1)
N$survival(1)
#> [1] 0.1586553
In the example above we:
survival
method does not
existExoticStatistics
decoratorThe CoreStatistics decorator includes methods for numeric
calculations, a generalised moments kthmoment
function and
a generalised expectation method genExp
. All methods can be
viewed using ?CoreStatistics
. In distr6 we have a strict
design principle that only analytic results should be provided as
methods in distributions, i.e. we only return results for which we know
the output is 100% accurate. The CoreStatistics
decorator
allows you to return numeric results when analytic ones aren’t
available. For example,
w <- Weibull$new()
# Error as the characteristic function doesn't exist
w$cf(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(w, "CoreStatistics")
#> Weibull is now decorated with CoreStatistics
#> Weibull(scale = 1, shape = 1)
# Warning as numerical integration used
w$cf(5)
#> Results from numeric calculations are approximate only. Better results may be available.
#> Results from numeric calculations are approximate only. Better results may be available.
#> [1] 0.03846162+0.1923076i
The decorator also introduces generalised moment and expectation
methods. The help documentation for these ?kthmoment
and
?genExp
give a full overview to these methods, but both are
very useful for modelling, inference and deriving other numeric
results.
The ExoticStatistics decorator includes more complex numeric methods
as well as survival, hazard and cumulative hazard that may or may not be
analytic expressions (depending what is available in the distribution
object). Once again all the methods added by this decorator can be
viewed using ?ExoticStatistics
. For example,
N <- Normal$new()
# Error as the characteristic function doesn't exist
N$hazard(1)
#> Error in eval(expr, envir, enclos): attempt to apply non-function
decorate(N, "ExoticStatistics")
#> Normal is now decorated with ExoticStatistics
#> Norm(mean = 0, var = 1)
# No warning as an analytic expression using pdf and cdf are used
N$hazard(1)
#> [1] 1.525135
# Warning as numeric calculations are used
N$pdfPNorm(2,0,4)
#> Results from numeric calculations are approximate only. Better results may be available.
#> [1] 0.3755628
The final implemented decorator is used to impute missing d/p/q/r
methods. We will return to the FunctionImputation
decorator
in a future
tutorial which looks at constructing custom distributions.
There are two main ways to decorate distributions in distr6, either in construction or after construction. We show these by example:
In Construction
Normal$new(decorators = "CoreStatistics")
#> Norm(mean = 0, var = 1)
Normal$new(decorators = c("CoreStatistics", "ExoticStatistics"))
#> Norm(mean = 0, var = 1)
After Construction
N <- Normal$new()
decorate(N, "CoreStatistics")
#> Normal is now decorated with CoreStatistics
#> Norm(mean = 0, var = 1)
And that’s all there is to it! If you forget which decorators are
available, just run listDecorators()
, or
listDecorators(simplify = FALSE)
if you want to see which
methods they include at the same time.
In this tutorial we looked at decorators in distr6 to obtain numeric results, methods for statistical modelling and imputation methods for missing d/p/q/r functions. In the next tutorial we look at the next big feature in distr6, wrappers.