Often times we encounter equations which cannot be solved using direct methods. Such systems of equations are commonly encountered within the context of maximum likelihood estimation, and in such cases, iterative methods can be used to obtain a solution.
Assume a set of observations representing ground-up property losses in dollars:
19999 19974 5051 7179 34416 56840 4420 6558
Our task is to fit a Weibull distribution to the loss data in order to produce a severity curve. The Weibull density is given by:
where:
is the shape parameter, is the scale parameter, . .
The expected value of the Weibull distribution is
and the median is given by
The variance is given by
In
The fitdistrplus library calculates parameter estimates given data and a hypothesized distribution. The fitdist
function takes an optional start
parameter, which represents initial parameter values associated with the hypothesized distribution. The Weibull distribution has two parameters that require estimation:
First, notice that if the mean is divided by the median,
As a consequence of the Gamma function in the right-hand-side numerator, we cannot solve for uniroot
to estimate roots of univariate functions numerically. In the code that follows, we implement a closure which returns a function which then can be evaluated and k
, it’s sole argument, which uniroot
will use to zero-in on a solution:
# Example solving for Weibull shape parameter using uniroot.
= c(19999, 19974, 5051, 7179, 34416, 56840, 4420, 6558)
lossData
# Calling shapeFunc returns a function, which can then be used by uniroot to find a solution.
= function(v) {
shapeFunc # Compute ratio of empirical mean to median.
= mean(v) / median(v)
ratio function(k) {
return((gamma(1 + (1 / k)) / (log(2)^(1 / k))) - ratio)
}
}
# Evaluate shapeFunc. ff is a function which takes a single argument `k`.
= shapeFunc(lossData) ff
The body of shapeFunc
is a straightforward implementation of our ratio expression above. The only difference is the expression is set to 0 by subtracting the ratio (1.421915) from both sides. We have our function ff
and the interval over which to search for a solution uniroot
is made below:
= uniroot(ff, interval=c(.Machine$double.eps, max(lossData)))$root shape
Since .Machine$double.eps
, which represents the smallest positive floating-point value
resulting in
Obtaining Maximum Likelihood Estimates
With our hypothesized distribution and initial parameters, obtaining maximum likelihood estimates is straightforward. The initial parameter estimation code is included again for convenience:
# Computing maximum likelihood estimates using fitdistrplus.
library("fitdistplus")
= c(19999, 19974, 5051, 7179, 34416, 56840, 4420, 6558)
lossData
= function(v) {
shapeFunc # Compute ratio of empirical mean to median.
= mean(v) / median(v)
ratio function(k) {
return((gamma(1 + (1 / k)) / (log(2)^(1 / k))) - ratio)
}
}
# Evaluate shapeFunc. ff is a function which takes a single argument `k`.
= shapeFunc(lossData)
ff
# Initial shape parameter estimate.
= uniroot(ff, interval=c(.Machine$double.eps, max(lossData)))$root
shape0
# Initial scale parameter estimate.
= mean(lossData) / gamma(1 + (1 / shape0))
scale0
# Obtain mle parameter estimates.
= fitdistrplus::fitdist(
mleFit distr="weibull", method="mle", start=list(shape=shape0, scale=scale0)
lossData, )
Accessing mleFit
’s estimate
attribute, parameter estimates are:
> mleFit$estimate
shape scale 1.177033 20525.761478
Which is close to our initial starting parameter estimates.