Nothing
### actuar: Actuarial Functions and Heavy Tailed Distributions
###
### Demo of the risk theory facilities provided by actuar
###
### AUTHORS: Christophe Dutang, Vincent Goulet <vincent.goulet@act.ulaval.ca>
require(actuar)
require(graphics)
### DISCRETIZATION OF CONTINUOUS DISTRIBUTIONS
## Upper and lower discretization of a Gamma(2, 1) distribution with a
## step (or span, or lag) of 0.5. The value of 'to' is chosen so as to
## cover most of the distribution.
x <- seq(0, qgamma(1 - 1E-6, 2, 1), by = 0.5)
xu <- tail(x, 1)
fu <- discretize(pgamma(x, 2, 1), method = "upper",
from = 0, to = xu, step = 0.5)
fl <- discretize(pgamma(x, 2, 1), method = "lower",
from = 0, to = xu, step = 0.5)
curve(pgamma(x, 2, 1), xlim = range(x), lwd = 2)
par(col = "blue")
plot(stepfun(head(x, -1), diffinv(fu)), pch = 19, add = TRUE)
par(col = "green")
plot(stepfun(x, diffinv(fl)), pch = 19, add = TRUE)
par(col = "black")
## Discretization with the rounding method, which has the true cdf
## pass through the midpoints of the intervals [x - step/2, x +
## step/2).
fr <- discretize(pgamma(x, 2, 1), method = "rounding",
from = 0, to = xu, step = 0.5)
curve(pgamma(x, 2, 1), xlim = range(x), lwd = 2)
par(col = "blue")
plot(stepfun(head(x, -1), diffinv(fr)), pch = 19, add = TRUE)
par(col = "black")
## Local matching of the first moment. This requires a function to
## compute the limited expected value of the true distribution in any
## point.
fb <- discretize(pgamma(x, 2, 1), method = "unbiased",
lev = levgamma(x, 2, 1),
from = 0, to = xu, step = 0.5)
curve(pgamma(x, 2, 1), xlim = range(x), lwd = 2)
par(col = "blue")
plot(stepfun(x, diffinv(fb)), pch = 19, add = TRUE)
par(col = "black")
all.equal(diff(pgamma(range(x), 2, 1)),
sum(fb)) # same total probability
all.equal(levgamma(xu, 2, 1) - xu * pgamma(xu, 2, 1, lower.tail = FALSE),
drop(crossprod(x, fb))) # same expected value
## Comparison of all four methods
fu <- discretize(plnorm(x), method = "upper", from = 0, to = 5)
fl <- discretize(plnorm(x), method = "lower", from = 0, to = 5)
fr <- discretize(plnorm(x), method = "rounding", from = 0, to = 5)
fb <- discretize(plnorm(x), method = "unbiased", from = 0, to = 5,
lev = levlnorm(x))
curve(plnorm(x), from = 0, to = 5, lwd = 2)
par(col = "blue")
plot(stepfun(0:4, diffinv(fu)), pch = 19, add = TRUE)
par(col = "red")
plot(stepfun(0:5, diffinv(fl)), pch = 19, add = TRUE)
par(col = "green")
plot(stepfun(0:4, diffinv(fr)), pch = 19, add = TRUE)
par(col = "magenta")
plot(stepfun(0:5, diffinv(fb)), pch = 19, add = TRUE)
legend("bottomright", legend = c("upper", "lower", "rounding", "unbiased"),
col = c("blue", "red", "green", "magenta"), lty = 1, pch = 19,
text.col = "black")
par(col = "black")
### CALCULATION OF THE AGGREGATE CLAIM AMOUNT DISTRIBUTION
## Calculation of the aggregate claim amount distribution using the
## recursive method (Panjer). Argument 'x.scale' is used to specify
## how much a value of 1 is really worth.
fx.b <- discretize(pgamma(x, 2, 1), from = 0, to = 22, step = 0.5,
method = "unbiased", lev = levgamma(x, 2, 1))
Fs.b <- aggregateDist("recursive", model.freq = "poisson",
model.sev = fx.b, lambda = 10, x.scale = 0.5)
summary(Fs.b) # summary method
knots(Fs.b) # support of Fs.b (knots)
Fs.b(knots(Fs.b)) # evaluation at knots
plot(Fs.b, do.points = FALSE, verticals = TRUE, xlim = c(0, 60)) # graphic
mean(Fs.b) # empirical mean
quantile(Fs.b) # quantiles
## Convolutions (exact calculation). Requires a vector of
## probabilities for the frequency model. This method can quickly
## become impractical for a large expected number of claims.
pn <- dpois(0:qpois(1-1E-6, 10), 10)
Fs <- aggregateDist("convolution", model.freq = pn, model.sev = fx.b,
x.scale = 0.5)
summary(Fs) # summary method
knots(Fs) # support of Fs (knots)
Fs(knots(Fs)) # evaluation at knots
plot(Fs, do.points = FALSE, verticals = TRUE, xlim = c(0, 60)) # graphic
mean(Fs) # empirical mean
quantile(Fs) # quantiles
## Normal approximation. Not hugely useful, but simple to implement...
Fs.n <- aggregateDist("normal", moments = c(20, 60))
summary(Fs.n) # summary method
plot(Fs.n, xlim = c(0, 60)) # graphic
mean(Fs.n) # true mean
quantile(Fs.n) # normal quantiles
## Normal Power II approximation. The approximation is valid for
## values above the expected value only.
Fs.np <- aggregateDist("npower", moments = c(20, 60, 0.516398))
summary(Fs.np) # summary method
plot(Fs.np, xlim = c(0, 60)) # truncated graphic
## Simulation method. Function 'simul' is used to simulate the data
## (see the 'simulation' demo for examples).
Fs.s <- aggregateDist("simulation",
model.freq = expression(y = rpois(10)),
model.sev = expression(y = rgamma(2, 1)),
nb.simul = 10000)
summary(Fs.s) # summary method
plot(Fs.s, do.points = FALSE, verticals = TRUE, xlim = c(0, 60)) # graphic
mean(Fs.s) # empirical mean
quantile(Fs.s) # quantiles
## Graphic comparing the cdfs obtained by a few methods.
fx.u <- discretize(pgamma(x, 2, 1), from = 0, to = 22, step = 0.5,
method = "upper")
Fs.u <- aggregateDist("recursive", model.freq = "poisson",
model.sev = fx.u, lambda = 10, x.scale = 0.5)
fx.l <- discretize(pgamma(x, 2, 1), from = 0, to = 22, step = 0.5,
method = "lower")
Fs.l <- aggregateDist("recursive", model.freq = "poisson",
model.sev = fx.l, lambda = 10, x.scale = 0.5)
par(col = "black")
plot(Fs.b, do.points = FALSE, verticals = TRUE, xlim = c(0, 60), sub = "")
par(col = "blue")
plot(Fs.u, do.points = FALSE, verticals = TRUE, add = TRUE, sub = "")
par(col = "red")
plot(Fs.l, do.points = FALSE, verticals = TRUE, add = TRUE, sub = "")
par(col = "green")
plot(Fs.s, do.points = FALSE, verticals = TRUE, add = TRUE, sub = "")
par(col = "magenta")
plot(Fs.n, add = TRUE, sub = "")
legend("bottomright",
legend = c("recursive + unbiased", "recursive + upper",
"recursive + lower", "simulation",
"normal approximation"),
col = c("black", "blue", "red", "green", "magenta"),
lty = 1, text.col = "black", cex = 1.2)
par(col = "black")
## Table of quantiles for the same methods as graphic above.
x <- knots(Fs.l)
m <- which.min(x[round(Fs.l(x), 6) > 0])
M <- which.max(x[round(Fs.u(x), 6) < 1])
x <- x[round(seq.int(from = m, to = M, length = 30))]
round(cbind(x = x,
Lower = Fs.l(x),
Unbiased = Fs.b(x),
Upper = Fs.u(x),
Simulation = Fs.s(x),
Normal = Fs.n(x)), 6)
### CALCULATION OF THE ADJUSTMENT COEFFICIENT
## No reinsurance, generalized Erlang claim amounts, inverse gamma
## interarrival times and independence. The adjustment coefficient is
## increasing with the safety loading.
mgf <- function(x) 1/(1 - x) * 2/(2 - x) * 3/(3 - x)
adjCoef(mgf, mgfinvgamma(x, 2, 6/11), 1.1, 1)
adjCoef(mgf, mgfinvgamma(x, 2, 6/11), 1.2, 1)
adjCoef(mgf, mgfinvgamma(x, 2, 6/11), 1.3, 1)
## More sophisticated example: comparison of the effect of dependence
## on the adjustment coefficient in the case of proportional
## reinsurance. Use a Clayton copula with exponential marginals.
rclayton <- function(alpha, n)
{
val <- cbind(runif(n), runif(n))
val[, 2] <- (val[, 1]^(-alpha) * (val[, 2]^(-alpha/(alpha + 1)) - 1) + 1)^(-1/alpha)
val
}
u <- rclayton(2, 1000) # variates with positive dependence
x <- qexp(u[, 1]) # claim amounts
w <- qexp(u[, 2]) # interarrival times
## Premium rate and Lundberg's functions of the retention rate. We
## assume a safety loading of 20% for the insurer and 30% for the
## reinsurer and premium calculated with the expected value principle.
p <- function(a) mean(x)/mean(w) * (1.2 - 1.3 + 1.3 * a)
h <- function(r, a) mean(exp(r * (a * x - p(a) * w)))
R1 <- adjCoef(h = h, upper = 1, reinsurance = "prop", from = 1/3, to = 1)
plot(R1)
## Repeat the above with independent claim amounts and interarrival
## times.
u <- rclayton(1, 1000) # independent variates
x <- qexp(u[,1]) # claim amounts
w <- qexp(u[,2]) # interarrival times
R2 <- adjCoef(h = h, upper = 1, reinsurance = "prop", from = 1/3, to = 1)
plot(R2, add = TRUE, col = "green")
legend("bottomright", legend = c("dependence", "independence"),
col = c("black", "green"), lty = 1)
## Similar example with excess-of-loss reinsurance.
## positive dependence
u <- rclayton(2, 1000) # variates with positive dependence
x <- qexp(u[,1]) # claim amounts
w <- qexp(u[,2]) # interarrival times
p <- function(L)
mean(x)/mean(w) * (1.2 - 1.3) + 1.3 * mean(pmin(L, x))/mean(w)
h <- function(r, L)
mean(exp(r * (pmin(L, x) - p(L) * w)))
R3 <- adjCoef(h = h, upper = 1, reinsurance = "prop", from = 0, to = 10)
plot(R3)
u <- rclayton(1, 1000) # independent variates
x <- qexp(u[,1]) # claim amounts
w <- qexp(u[,2]) # interarrival times
R4 <- adjCoef(h = h, upper = 1, reinsurance = "prop", from = 0, to = 10)
plot(R4, add = TRUE, col = "green")
legend("bottomright", legend = c("dependence", "independence"),
col = c("black", "green"), lty = 1)
### CALCULATION OF RUIN PROBABILITIES
## Case with an explicit formula: exponential claims and interarrival
## times. Safety loading is always 20% and premiums are always
## calculated according to the expected value principle.
psi <- ruin(claims = "exponential",
par.claims = list(rate = 1),
wait = "exponential",
par.wait = list(rate = 1),
premium = 1.2)
psi(0:10)
plot(psi, from = 0, to = 10)
## Exponential claims and hyper-exponential interarrival times.
psi <- ruin(claims = "exponential",
par.claims = list(rate = 2),
wait = "exponential",
par.wait = list(rate = c(2, 3, 1)/2, w = c(2, 3, 1)/6),
premium = 1.2)
psi(0:10)
## Hyper-exponential claims and interarrival times.
psi <- ruin(claims = "exponential",
par.claims = list(rate = c(2, 3, 1)/2, w = c(2, 3, 1)/6),
wait = "exponential",
par.wait = list(rate = c(2, 3, 1)/4, w = c(2, 3, 1)/6),
premium = 0.6)
psi(0:10)
## Exponential claims and Erlang interarrival times
psi <- ruin(claims = "exponential",
par.claims = list(rate = 2),
wait = "Erlang",
par.wait = list(shape = 2, rate = 1),
premium = 1.2)
psi(0:10)
## Erlang claims and interarrival times
psi <- ruin(claims = "Erlang",
par.claims = list(shape = 2, rate = 2),
wait = "Erlang",
par.wait = list(shape = 2, rate = 1),
premium = 0.6)
psi(0:10)
## Mixture of Erlang for claims and Erlang interarrival times
psi <- ruin(claims = "Erlang",
par.claims = list(shape = c(2, 4), rate = c(1, 3),
w = c(1, 2)/3),
wait = "Erlang",
par.wait = list(shape = 2, rate = 1),
premium = 1.2)
psi(0:10)
## Generalized Erlang claims and mixture of two generalized Erlang
## interarrival times. These must be given as phase-type distributions
## to 'ruin'.
prob.c <- c(1, 0, 2, 0)/3
rate.c <- cbind(c(-1, 0, 0, 0), c(1, -3, 0, 0),
c(0, 0, -2, 0), c(0, 0, 2, -3))
mean.c <- mphtype(1, prob.c, rate.c)
prob.w <- c(1, 0, 0)
rate.w <- cbind(c(-1, 0, 0), c(1, -2, 0), c(0, 2, -3))
mean.w <- mphtype(1, prob.w, rate.w)
psi <- ruin(claims = "phase-type",
par.claims = list(prob = prob.c, rate = rate.c),
wait = "phase-type",
par.wait = list(prob = prob.w, rate = rate.w),
premium = 1.2 * mean.c/mean.w)
psi(0:10)
par(op)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.