R/Common.R

Defines functions toDate nloglik expectZeros simP0 rreopen ultiDevFac plotText rtempirical qtempirical ptempirical dtempirical rtweibull qtweibull ptweibull dtweibull rtpois qtpois ptpois dtpois rtpareto qtpareto ptpareto dtpareto rtnbinom qtnbinom ptnbinom dtnbinom rtlnorm qtlnorm ptlnorm dtlnorm rtgeom qtgeom ptgeom dtgeom rtgamma qtgamma ptgamma dtgamma rtexp qtexp ptexp dtexp rtbeta qtbeta ptbeta dtbeta rtnorm qtnorm ptnorm dtnorm dempirical rempirical qempirical pempirical truncate rpareto qpareto ppareto dpareto mpareto

Documented in dempirical dpareto dtbeta dtempirical dtexp dtgamma dtgeom dtlnorm dtnbinom dtnorm dtpareto dtpois dtweibull expectZeros mpareto nloglik pempirical plotText ppareto ptbeta ptempirical ptexp ptgamma ptgeom ptlnorm ptnbinom ptnorm ptpareto ptpois ptweibull qempirical qpareto qtbeta qtempirical qtexp qtgamma qtgeom qtlnorm qtnbinom qtnorm qtpareto qtpois qtweibull rempirical rpareto rreopen rtbeta rtempirical rtexp rtgamma rtgeom rtlnorm rtnbinom rtnorm rtpareto rtpois rtweibull simP0 toDate truncate ultiDevFac

# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

#' Moment function of Pareto Distribution (PDF: alpha*xm^alpha/x^(alpha+1))
#' @param order Order of moment
#' @param xm Threshold value
#' @param alpha Default=3
#' @examples
#' mpareto(1, 1000, 2)
#' @rdname pareto
#' @export
mpareto <- function(order, xm, alpha = 3) {
  if (order == 1 && alpha > 1) {
    return(alpha * xm / (alpha - 1))
  } else if (order == 1 && alpha <= 1) {
    return(Inf)
  } else if (order == 2 && alpha > 2) {
    return(xm^2 * alpha / (alpha - 1)^2 / (alpha - 2) + (alpha * xm / (alpha - 1))^2)
  } else {
    return(Inf)
  }
}

#' Density function of Pareto Distribution (PDF: alpha*xm^alpha/x^(alpha+1))
#' @param x Value of the variable
#' @examples
#' dpareto(1500, 1000, 2)
#' @rdname pareto
#' @export
dpareto <- function(x, xm, alpha = 3) ifelse(x > xm, alpha * xm^alpha / (x^(alpha + 1)), 0)

#' Cumulative probability function of Pareto Distribution (CDF: 1-(xm/x)^alpha)
#' @param q Value of the variable
#' @examples
#' ppareto(1500, 1000, 2)
#' @rdname pareto
#' @export
ppareto <- function(q, xm, alpha = 3) ifelse(q > xm, 1 - (xm / q)^alpha, 0)

#' Quantile function of Pareto Distribution
#' @param p Value of the probability
#' @examples
#' qpareto(0.5, 1000, 2)
#' @rdname pareto
#' @export
qpareto <- function(p, xm, alpha = 3) ifelse(p < 0 | p > 1, NaN, xm * (1 - p)^(-1 / alpha))

#' Random generation of Pareto Distribution
#' @param n Number of samples
#' @examples
#' rpareto(100, 1000, 2)
#' @rdname pareto
#' @export
rpareto <- function(n, xm, alpha = 3) qpareto(runif(n), xm, alpha)


#' Truncate a numeric vector
#' @param x A numeric vector
#' @param lower Lower bound
#' @param upper Upper bound
#' @examples
#' trunc(rnorm(100, 3, 6), 0, 7)
#' @rdname truncate
#' @export
truncate <- function(x, lower, upper) {
  x[x > upper] <- upper
  x[x < lower] <- lower
  return(x)
}

#' Cumulative probability function of empirical distribution using linear interpolation
#' @param q Value of the variable
#' @param cdf empirical distribution (cdf for continuous distribution and pmf for discrete distribution)
#' @examples
#' # discrete distribution
#' pempirical(c(3, 5, 10), matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2))
#' # continuous distribution
#' pempirical(350, matrix(c(seq(0.01, 1, 0.01), cumprod(c(1, rep(1.1, 99)))), 100, 2))
#' @rdname empirical
#' @export
pempirical <- function(q, cdf) {
  if (length(unique(cdf[, 2])) == 1) {
    return(runif(length(q)))
  } else if (sum(cdf[, 1]) > 1 & cdf[nrow(cdf), 1] == 1) { # cumulative probability function for continuous distribution
    return(approx(cdf[, 2], cdf[, 1], xout = q, rule = 2)$y)
  } else if (sum(cdf[, 1]) > 1 & cdf[nrow(cdf), 1] < 1) {
    warning("cdf input is not complete. The last row does not have a cumulative probability of 1. It will be extrapolated to 1.")
    nx <- nrow(cdf)
    xend <- (cdf[nx, 2] - cdf[nx - 1, 2]) / (cdf[nx, 1] - cdf[nx - 1, 1]) * (1 - cdf[nx - 1, 1]) + cdf[nx - 1, 2]
    cdfnew <- rbind(cdf, c(1, xend))
    return(approx(cdfnew[, 2], cdfnew[, 1], xout = q, rule = 2)$y)
  } else { # probability mass function for discrete distribution
    ps <- cdf[, 1] / sum(cdf[, 1])
    y <- as.vector(q)
    l <- length(y)
    z <- rep(0, l)
    for (i in 1:l) z[i] <- sum(ps[cdf[, 2] <= y[i]])
    z <- as.numeric(z)
    if (is.array(q)) {
      dim(z) <- dim(q)
    }
    return(z)
  }
}

#' Quantile function of Empirical Distribution
#' @param p Value of the probability
#' @examples
#' # discrete distribution
#' qempirical(c(0.3, 0.65, 1), matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2))
#' # continuous distribution
#' qempirical(c(0.3, 0.65, 0.8), matrix(c(seq(0.01, 1, 0.01), cumprod(c(1, rep(1.1, 99)))), 100, 2))
#' @rdname empirical
#' @export
qempirical <- function(p, cdf) {
  if (sum(cdf[, 1]) > 1 && cdf[nrow(cdf), 1] == 1) { # cumulative probability function for continuous distribution
    return(approx(cdf[, 1], cdf[, 2], xout = p, rule = 2)$y)
  } else if (sum(cdf[, 1]) > 1 && cdf[nrow(cdf), 1] < 1) {
    warning("cdf input is not complete. The last row does not have a cumulative probability of 1. It will be extrapolated to 1.")
    nx <- nrow(cdf)
    xend <- (cdf[nx, 2] - cdf[nx - 1, 2]) / (cdf[nx, 1] - cdf[nx - 1, 1]) * (1 - cdf[nx - 1, 1]) + cdf[nx - 1, 2]
    cdfnew <- rbind(cdf, c(1, xend))
    return(approx(cdfnew[, 1], cdfnew[, 2], xout = p, rule = 2)$y)
  } else { # probability mass function for discrete distribution
    ps <- cumsum(cdf[, 1]) / sum(cdf[, 1])
    y <- as.vector(p)
    l <- length(y)
    z <- rep(0, l)
    for (i in 1:l) z[i] <- length(cdf[, 2]) - sum(y[i] <= ps) + 1
    z <- as.numeric(z)
    z <- cdf[, 2][z]
    if (is.array(q)) {
      dim(z) <- dim(q)
    }
    return(z)
  }
}

#' Random generation function of Empirical Distribution
#' @param n Number of samples
#' @examples
#' # discrete distribution
#' rempirical(100, matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2))
#' # continuous distribution
#' rempirical(100, matrix(c(seq(0.01, 1, 0.01), cumprod(c(1, rep(1.1, 99)))), 100, 2))
#' @rdname empirical
#' @export
rempirical <- function(n, cdf) {
  if (sum(cdf[, 1]) > 1 && cdf[nrow(cdf), 1] == 1) { # cumulative probability function for continuous distribution
    return(qempirical(runif(n), cdf))
  } else if (sum(cdf[, 1]) > 1 && cdf[nrow(cdf), 1] < 1) {
    warning("cdf input is not complete. The last row does not have a cumulative probability of 1. It will be extrapolated to 1.")
    nx <- nrow(cdf)
    xend <- (cdf[nx, 2] - cdf[nx - 1, 2]) / (cdf[nx, 1] - cdf[nx - 1, 1]) * (1 - cdf[nx - 1, 1]) + cdf[nx - 1, 2]
    cdfnew <- rbind(cdf, c(1, xend))
    return(qempirical(runif(n), cdfnew))
  } else { # probability mass function for discrete distribution
    ps <- cdf[, 1] / sum(cdf[, 1])
    return(sample(x = cdf[, 2], size = n, replace = TRUE, prob = ps))
  }
}

#' Density function of Empirical Distribution based on simulation
#' @param x Value of the variable
#' @examples
#' # discrete distribution
#' dempirical(3, matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2))
#' # continuous distribution
#' dempirical(30, matrix(c(seq(0.01, 1, 0.01), qnorm(seq(0.01, 1, 0.01), 30, 20)), 100, 2))
#' @rdname empirical
#'
#' @import stats
#'
#' @export
dempirical <- function(x, cdf) {
  sdf <- approxfun(density(rempirical(100000, cdf)))
  return(sdf(x))
}

#' Density function of Truncated Normal Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param mean Mean of the untruncated Normal distribution
#' @param sd Standard deviation of the untruncated Normal distribution
#' @param min Left truncation (like deductible)
#' @param max Right truncation (like limit)
#' @examples
#' dtnorm(0.5, 1, 2)
#' @rdname tnorm
#' @export
dtnorm <- function(x, mean, sd, min = 0, max = 1e+9) {
  ifelse(x == 0, pnorm(min, mean, sd),
    ifelse(x >= (max - min - 1e-10), 1 - pnorm(max, mean, sd),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dnorm(x + min, mean = mean, sd = sd), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Normal Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptnorm(0.5, 1, 2)
#' @rdname tnorm
#' @export
ptnorm <- function(q, mean, sd, min = 0, max = 1e+9) {
  ifelse(q == 0, pnorm(min, mean, sd),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pnorm(q + min, mean = mean, sd = sd), 0)
      )
    )
  )
}

#' Quantile function of Truncated Normal Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtnorm(0.5, 1, 2)
#' @rdname tnorm
#' @export
qtnorm <- function(p, mean, sd, min = 0, max = 1e+9) {
  ifelse(p <= pnorm(min, mean, sd), 0,
    ifelse(p >= pnorm(max, mean, sd), max - min, qnorm(p, mean = mean, sd = sd) - min)
  )
}

#' Random generation of Truncated Normal Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtnorm(100, 1, 2)
#' @rdname tnorm
#' @export
rtnorm <- function(n, mean, sd, min = 0, max = 1e+9) {
  qtnorm(runif(n), mean = mean, sd = sd, min, max)
}



#' Density function of Truncated Beta Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param shape1 distribution parameter
#' @param shape2 distribution parameter
#' @param ncp non-centrality parameter (Default: 0)
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtbeta(0.6, 1, 2)
#' @rdname tbeta
#' @export
dtbeta <- function(x, shape1, shape2, ncp = 0, min = 0, max = 1) {
  ifelse(x == 0, pbeta(min, shape1, shape2, ncp),
    ifelse(x >= (max - min - 1e-10), 1 - pbeta(max, shape1, shape2, ncp),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dbeta(x + min, shape1, shape2, ncp), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Beta Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptbeta(0.5, 1, 2)
#' @rdname tbeta
#' @export
ptbeta <- function(q, shape1, shape2, ncp = 0, min = 0, max = 1) {
  ifelse(q == 0, pbeta(min, shape1, shape2, ncp),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pbeta(q + min, shape1, shape2, ncp), 0)
      )
    )
  )
}

#' Quantile function of Truncated Beta Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtbeta(0.5, 1, 2)
#' @rdname tbeta
#' @export
qtbeta <- function(p, shape1, shape2, ncp = 0, min = 0, max = 1) {
  ifelse(p <= pbeta(min, shape1, shape2, ncp), 0,
    ifelse(p >= pbeta(max, shape1, shape2, ncp), max - min, qbeta(p, shape1, shape2, ncp) - min)
  )
}

#' Random generation of Truncated Beta Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtbeta(100, 1, 2)
#' @rdname tbeta
#' @export
rtbeta <- function(n, shape1, shape2, ncp = 0, min = 0, max = 1) {
  qtbeta(runif(n), shape1, shape2, ncp, min, max)
}



#' Density function of Truncated Exponential Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param rate Distribution parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtexp(5, 0.1)
#' @rdname texp
#' @export
dtexp <- function(x, rate, min = 0, max = 1e+9) {
  ifelse(x == 0, pexp(min, rate),
    ifelse(x >= (max - min - 1e-10), 1 - pexp(max, rate),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dexp(x + min, rate), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Exponential Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptexp(5, 0.1)
#' @rdname texp
#' @export
ptexp <- function(q, rate, min = 0, max = 1e+9) {
  ifelse(q == 0, pexp(min, rate),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pexp(q + min, rate), 0)
      )
    )
  )
}

#' Quantile function of Truncated Exponential Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtexp(0.5, 0.1)
#' @rdname texp
#' @export
qtexp <- function(p, rate, min = 0, max = 1e+9) {
  ifelse(p <= pexp(min, rate), 0,
    ifelse(p >= pexp(max, rate), max - min, qexp(p, rate) - min)
  )
}

#' Random generation of Truncated Exponential Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtexp(100, 0.1)
#' @rdname texp
#' @export
rtexp <- function(n, rate, min = 0, max = 1e+9) {
  qtexp(runif(n), rate, min, max)
}



#' Density function of Truncated Gamma Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param shape Shape parameter
#' @param scale Scale parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtgamma(2, 3, 2)
#' @rdname tgamma
#' @export
dtgamma <- function(x, shape, scale, min = 0, max = 1e+9) {
  ifelse(x == 0, pgamma(min, shape, scale),
    ifelse(x >= (max - min - 1e-10), 1 - pgamma(max, shape, scale),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dgamma(x + min, shape, scale), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Gamma Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptgamma(2, 3, 2)
#' @rdname tgamma
#' @export
ptgamma <- function(q, shape, scale, min = 0, max = 1e+9) {
  ifelse(q == 0, pgamma(min, shape, scale),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pgamma(q + min, shape, scale), 0)
      )
    )
  )
}

#' Quantile function of Truncated Gamma Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtgamma(0.5, 3, 2)
#' @rdname tgamma
#' @export
qtgamma <- function(p, shape, scale, min = 0, max = 1e+9) {
  ifelse(p <= pgamma(min, shape, scale), 0,
    ifelse(p >= pgamma(max, shape, scale), max - min, qgamma(p, shape, scale) - min)
  )
}

#' Random generation of Truncated Gamma Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtgamma(100, 3, 2)
#' @rdname tgamma
#' @export
rtgamma <- function(n, shape, scale, min = 0, max = 1e+9) {
  qtgamma(runif(n), shape, scale, min, max)
}



#' Density function of Truncated Geometric Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param prob Distribution parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtgeom(3, 0.3)
#' @rdname tgeom
#' @export
dtgeom <- function(x, prob, min = 0, max = 1e+9) {
  ifelse(x == 0, pgeom(min, prob),
    ifelse(x >= (max - min - 1e-10), 1 - pgeom(max, prob),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dgeom(x + min, prob), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Geometric Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptgeom(3, 0.3)
#' @rdname tgeom
#' @export
ptgeom <- function(q, prob, min = 0, max = 1e+9) {
  ifelse(q == 0, pgeom(min, prob),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pgeom(q + min, prob), 0)
      )
    )
  )
}

#' Quantile function of Truncated Geometric Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtgeom(0.7, 0.3)
#' @rdname tgeom
#' @export
qtgeom <- function(p, prob, min = 0, max = 1e+9) {
  ifelse(p <= pgeom(min, prob), 0,
    ifelse(p >= pgeom(max, prob), max - min, qgeom(p, prob) - min)
  )
}

#' Random generation of Truncated Geometric Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtgeom(100, 0.3)
#' @rdname tgeom
#' @export
rtgeom <- function(n, prob, min = 0, max = 1e+9) {
  qtgeom(runif(n), prob, min, max)
}



#' Density function of Truncated Lognormal Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param meanlog Mean of the log of the distribution
#' @param sdlog Standard deviation of the log of the distribution
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtlnorm(20, 3, 0.5)
#' @rdname tlnorm
#' @export
dtlnorm <- function(x, meanlog, sdlog, min = 0, max = 1e+9) {
  ifelse(x == 0, plnorm(min, meanlog, sdlog),
    ifelse(x >= (max - min - 1e-10), 1 - plnorm(max, meanlog, sdlog),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dlnorm(x + min, meanlog, sdlog), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Lognormal Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptlnorm(20, 3, 0.5)
#' @rdname tlnorm
#' @export
ptlnorm <- function(q, meanlog, sdlog, min = 0, max = 1e+9) {
  ifelse(q == 0, plnorm(min, meanlog, sdlog),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), plnorm(q + min, meanlog, sdlog), 0)
      )
    )
  )
}

#' Quantile function of Truncated Lognormal Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtlnorm(0.5, 3, 0.5)
#' @rdname tlnorm
#' @export
qtlnorm <- function(p, meanlog, sdlog, min = 0, max = 1e+9) {
  ifelse(p <= plnorm(min, meanlog, sdlog), 0,
    ifelse(p >= plnorm(max, meanlog, sdlog), max - min, qlnorm(p, meanlog, sdlog) - min)
  )
}

#' Random generation of Truncated Lognormal Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtlnorm(100, 3, 0.5)
#' @rdname tlnorm
#' @export
rtlnorm <- function(n, meanlog, sdlog, min = 0, max = 1e+9) {
  qtlnorm(runif(n), meanlog, sdlog, min, max)
}



#' Density function of Truncated Negative Binomial Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param size Number of successful trials
#' @param prob Probability of success in each trial
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtnbinom(230, 100, 0.3)
#' @rdname tnbinom
#' @export
dtnbinom <- function(x, size, prob, min = 0, max = 1e+9) {
  ifelse(x == 0, pnbinom(min, size, prob),
    ifelse(x >= (max - min - 1e-10), 1 - pnbinom(max, size, prob),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dnbinom(x + min, size, prob), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Negative Binomial Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptnbinom(230, 100, 0.3)
#' @rdname tnbinom
#' @export
ptnbinom <- function(q, size, prob, min = 0, max = 1e+9) {
  ifelse(q == 0, pnbinom(min, size, prob),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pnbinom(q + min, size, prob), 0)
      )
    )
  )
}

#' Quantile function of Truncated Negative Binomial Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtnbinom(0.5, 100, 0.3)
#' @rdname tnbinom
#' @export
qtnbinom <- function(p, size, prob, min = 0, max = 1e+9) {
  ifelse(p <= pnbinom(min, size, prob), 0,
    ifelse(p >= pnbinom(max, size, prob), max - min, qnbinom(p, size, prob) - min)
  )
}

#' Random generation of Truncated Negative Binomial Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtnbinom(500, 100, 0.3)
#' @rdname tnbinom
#' @export
rtnbinom <- function(n, size, prob, min = 0, max = 1e+9) {
  qtnbinom(runif(n), size, prob, min, max)
}



#' Density function of Truncated Pareto Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param xm Threshold value
#' @param alpha Model parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtpareto(500, 1000, 2)
#' @rdname tpareto
#' @export
dtpareto <- function(x, xm, alpha, min = xm, max = 1e+9) {
  ifelse(x == 0, ppareto(min, xm, alpha),
    ifelse(x >= (max - min - 1e-10), 1 - ppareto(max, xm, alpha),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dpareto(x + min, xm, alpha), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Pareto Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptpareto(500, 1000, 2)
#' @rdname tpareto
#' @export
ptpareto <- function(q, xm, alpha, min = xm, max = 1e+9) {
  ifelse(q == 0, ppareto(min, xm, alpha),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), ppareto(q + min, xm, alpha), 0)
      )
    )
  )
}

#' Quantile function of Truncated Pareto Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtpareto(0.5, 1000, 2)
#' @rdname tpareto
#' @export
qtpareto <- function(p, xm, alpha, min = xm, max = 1e+9) {
  ifelse(p <= ppareto(min, xm, alpha), 0,
    ifelse(p >= ppareto(max, xm, alpha), max - min, qpareto(p, xm, alpha) - min)
  )
}

#' Random generation of Truncated Pareto Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtpareto(100, 1000, 2)
#' @rdname tpareto
#' @export
rtpareto <- function(n, xm, alpha, min = xm, max = 1e+9) {
  qtpareto(runif(n), xm, alpha, min, max)
}



#' Density function of Truncated Poisson Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param lambda Distribution parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtpois(3, 5)
#' @rdname tpois
#' @export
dtpois <- function(x, lambda, min = 0, max = 1e+9) {
  ifelse(x == 0, ppois(min, lambda),
    ifelse(x >= (max - min - 1e-10), 1 - ppois(max, lambda),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dpois(x + min, lambda), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Poisson Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptpois(3, 5)
#' @rdname tpois
#' @export
ptpois <- function(q, lambda, min = 0, max = 1e+9) {
  ifelse(q == 0, ppois(min, lambda),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), ppois(q + min, lambda), 0)
      )
    )
  )
}

#' Quantile function of Truncated Poisson Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtpois(0.6, 5)
#' @rdname tpois
#' @export
qtpois <- function(p, lambda, min = 0, max = 1e+9) {
  ifelse(p <= ppois(min, lambda), 0,
    ifelse(p >= ppois(max, lambda), max - min, qpois(p, lambda) - min)
  )
}

#' Random generation of Truncated Poisson Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtpois(100, 5)
#' @rdname tpois
#' @export
rtpois <- function(n, lambda, min = 0, max = 1e+9) {
  qtpois(runif(n), lambda, min, max)
}



#' Density function of Truncated Weibull Distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param shape Shape parameter
#' @param scale Scale parameter
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' dtweibull(2.5, 2, 3)
#' @rdname tweibull
#' @export
dtweibull <- function(x, shape, scale, min = 0, max = 1e+9) {
  ifelse(x == 0, pweibull(min, shape, scale),
    ifelse(x >= (max - min - 1e-10), 1 - pweibull(max, shape, scale),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dweibull(x + min, shape, scale), 0)
      )
    )
  )
}

#' Cumulative probability function of Truncated Weibull Distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' ptweibull(2.5, 2, 3)
#' @rdname tweibull
#' @export
ptweibull <- function(q, shape, scale, min = 0, max = 1e+9) {
  ifelse(q == 0, pweibull(min, shape, scale),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pweibull(q + min, shape, scale), 0)
      )
    )
  )
}

#' Quantile function of Truncated Weibull Distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' qtweibull(0.5, 2, 3)
#' @rdname tweibull
#' @export
qtweibull <- function(p, shape, scale, min = 0, max = 1000000000) {
  ifelse(p <= pweibull(min, shape, scale), 0,
    ifelse(p >= pweibull(max, shape, scale), max - min, qweibull(p, shape, scale) - min)
  )
}

#' Random generation of Truncated Weibull Distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' rtweibull(100, 2, 3)
#' @rdname tweibull
#' @export
rtweibull <- function(n, shape, scale, min = 0, max = 1e+9) {
  qtweibull(runif(n), shape, scale, min, max)
}



#' Density function of truncated empirical distribution
#' @param x Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @param cdf empirical distribution (cdf for continuous distribution and pmf for discrete distribution)
#' @param min Left truncation deductible
#' @param max Right truncation limit
#' @examples
#' # discrete distribution
#' dtempirical(3, matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2), 3, 100)
#' # continuous distribution
#' dtempirical(30, matrix(c(seq(0.01, 1, 0.01), qnorm(seq(0.01, 1, 0.01), 30, 20)), 100, 2), 200, 10000000)
#' @rdname tempirical
#' @export
dtempirical <- function(x, cdf, min = 0, max = 1e+9) {
  ifelse(x == 0, pempirical(min, cdf),
    ifelse(x >= (max - min - 1e-10), 1 - pempirical(max, cdf),
      ifelse(x < 0, 0,
        ifelse(x < (max - min), dempirical(x + min, cdf), 0)
      )
    )
  )
}

#' Cumulative probability function of truncated empirical distribution
#' @param q Value of the variable after deductible and limit max(0,min(claim,limit)-deductible)
#' @examples
#' # discrete distribution
#' ptempirical(c(3, 5, 10), matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2), 3, 100)
#' # continuous distribution
#' ptempirical(350, matrix(c(seq(0.01, 1, 0.01), cumprod(c(1, rep(1.1, 99)))), 100, 2), 200, 10000000)
#' @rdname tempirical
#' @export
ptempirical <- function(q, cdf, min = 0, max = 100000) {
  ifelse(q == 0, pempirical(min, cdf),
    ifelse(q >= (max - min) - 1e-10, 1,
      ifelse(q < 0, 0,
        ifelse(q < (max - min), pempirical(q + min, cdf), 0)
      )
    )
  )
}

#' Quantile function of truncated empirical distribution max(0,min(claim,limit)-deductible)
#' @param p Value of the probability
#' @examples
#' # discrete distribution
#' qtempirical(c(0.3, 0.65, 1), matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2), 3, 100)
#' # continuous distribution
#' qtempirical(c(0.3, 0.65, 0.8), matrix(c(
#'   seq(0.01, 1, 0.01),
#'   cumprod(c(1, rep(1.1, 99)))
#' ), 100, 2), 200, 10000000)
#' @rdname tempirical
#' @export
qtempirical <- function(p, cdf, min = 0, max = 100000) {
  ifelse(p <= pempirical(min, cdf), 0,
    ifelse(p >= pempirical(max, cdf), max - min, qempirical(p, cdf) - min)
  )
}

#' Random generation of Truncated empirical distribution max(0,min(claim,limit)-deductible)
#' @param n Number of samples
#' @examples
#' # discrete distribution
#' rtempirical(100, matrix(c(0.1, 0.2, 0.3, 0.05, 0.05, 0.2, 0.1, 1:6, 10), 7, 2), 3, 100)
#' # continuous distribution
#' rtempirical(100, matrix(c(seq(0.01, 1, 0.01), cumprod(c(1, rep(1.1, 99)))), 100, 2), 200, 10000000)
#' @rdname tempirical
#' @export
rtempirical <- function(n, cdf, min = 0, max = 100000) {
  qtempirical(runif(n), cdf, min, max)
}


#' Plot text content
#' @param content A string to plot
#' @examples
#' plotText("You are awesome!")
#' @rdname plotText
#'
#' @import graphics
#' @export
plotText <- function(content) {
  par(font = 2, ps = 10, mar = c(4, 4, 1, 1), cex.main = 0.7, cex.sub = 0.8, cex.lab = 0.8, cex.axis = 0.8) # mfrow = c(1,1),
  plot(0:100, 0:100, type = "n", xlab = "", ylab = "", axes = FALSE)
  text(45, 45, content)
}

#' Calculate ultimate development factor based on current development year, a mean development factor schedule and its volatility. It is used to simulate the ultimate loss for open claims.
#' @param Years Include two columns: Current development year and Settlement Year
#' @param meanDevFac A vector that contains the expected development factor schedule for Normal distribution. It is mu for Lognormal distribution and shape for Gamma distribution.
#' @param sdDevFac A vector that contains the standard deviation of expected development factor schedule for Normal distribution. It is sigma for Lognormal distribution and scale for Gamma distribution.
#' @param distType distribution type for development factor. It can be "normal", "lognormal" or "gamma".
#' @examples
#' meanfac <- c(1.1, 1.08, 1.05, 1.03, 1.01, 1)
#' volfac <- rep(0.02, 6)
#' years <- matrix(c(1:6), 3, 2)
#' ultiDevFac(years, meanfac, volfac)
#' @rdname ultiDevFac
#' @export
ultiDevFac <- function(Years, meanDevFac, sdDevFac = rep(0, length(meanDevFac)), distType = "normal") {
  nDevFac <- pmin(length(meanDevFac), Years[, 2] - 1)
  n <- length(meanDevFac)
  result <- vector()
  for (i in c(1:length(nDevFac))) {
    if (is.na(nDevFac[i]) == TRUE) {
      result <- c(result, NA)
    } else {
      DevFac <- vector()
      if (distType == "normal") {
        DevFac <- meanDevFac + rnorm(n) * sdDevFac
      } else if (distType == "lognormal") {
        for (j in 1:n) {
          DevFac <- c(DevFac, rlnorm(1, meanlog = meanDevFac[j], sdlog = sdDevFac[j]))
        }
      } else if (distType == "gamma") {
        for (j in 1:n) {
          DevFac <- c(DevFac, rgamma(1, shape = meanDevFac[j], scale = sdDevFac[j]))
        }
      } else {
        DevFac <- rep(1, n)
      }

      if (Years[i, 1] == Years[i, 2]) {
        result <- c(result, 1)
      } else {
        result <- c(result, prod(DevFac[pmin(Years[i, 1], nDevFac[i]):nDevFac[i]]))
      }
    }
  }
  result
}

#' Simulate whether closed claims will be reopened or not.
#' @param closeYear Years after claim closure. It could be a number or a numeric vector.
#' @param reopenProb A vector that contains the reopen probability based on closeYear.
#' @examples
#' reopenprob <- c(0.02, 0.01, 0.005, 0.005, 0.003, 0)
#' rreopen(rep(2, 1000), reopenprob)
#' @rdname rreopen
#' @export
rreopen <- function(closeYear, reopenProb) {
  nDevFac <- length(reopenProb)
  ifelse(runif(length(closeYear)) <= reopenProb[pmin(closeYear, nDevFac)], 1, 0)
}

#' Simulate whether claims will have zero payment.
#' @param devYear Development Year. It could be a number or a numeric vector.
#' @param zeroProb A vector that contains the probability of zero payment based on development year.
#' @examples
#' zeroprob <- c(0.02, 0.01, 0.005, 0.005, 0.003, 0)
#' simP0(rep(2, 1000), zeroprob)
#' @rdname simP0
#' @export
simP0 <- function(devYear, zeroProb) {
  nDevFac <- length(zeroProb)
  ifelse(runif(length(devYear)) <= zeroProb[pmin(devYear, nDevFac)], 0, 1)
}

#' Get the expected P0 based on settlement/close year.
#' @param closeYear Development years that claims are settled. It could be a number or a numeric vector.
#' @param zeroProb A vector that contains the P(0) based on development year.
#' @examples
#' zeroprob <- c(0.02, 0.01, 0.005, 0.005, 0.003, 0)
#' expectZeros(c(2, 3, 6, 9, 100, 1, 2, 3, 4), zeroprob)
#' @rdname expectZeros
#' @export
expectZeros <- function(closeYear, zeroProb) {
  nProb <- length(zeroProb)
  zeroProb[pmin(closeYear, nProb)]
}

#' Negative Loglikelihood.
#' @param paras A vector contain distribution parameters.
#' @param dist A Distribution Object.
#' @param fitdata A vector of loss data for fitting.
#' @param deductible A vector of deductible data for all loss data.
#' @param limit A vector of limit data for all loss data.
#' @examples
#' paras <- c(1, 1)
#' dist <- new("Normal")
#' fitdata <- rtnorm(1000, 3, 2, 1, 10)
#' deductible <- rep(1, 1000)
#' limit <- rep(9, 1000)
#' nloglik(paras, dist, fitdata, deductible, limit)
#' paras <- c(3, 2)
#' nloglik(paras, dist, fitdata, deductible, limit)
#'
#' @rdname loglik
#' @export
nloglik <- function(paras, dist, fitdata, deductible, limit) {
  if (length(paras) == 1) {
    dist@p1 <- paras[1]
  } else if (length(paras) == 2) {
    dist@p1 <- paras[1]
    dist@p2 <- paras[2]
  } else if (length(paras) == 3) {
    dist@p1 <- paras[1]
    dist@p2 <- paras[2]
    dist@p3 <- paras[3]
  }

  loglik <- rep(0, length(fitdata))

  withinlimit <- ifelse((is.na(limit) | (fitdata < limit)), TRUE, FALSE)

  loglik <- ifelse(withinlimit, log(Density(dist, (fitdata + deductible))), (1 - Probability(dist, (limit + deductible))))
  loglik <- loglik - log(1 - Probability(dist, deductible))

  return(-sum(loglik))
}


#' Convert US date mm/dd/yyyy to yyyy-mm-dd format
#' @param d vector of dates in possible US format
#' @examples
#' toDate("3/5/2017")
#' @rdname toDate
#' @export
toDate <- function(d) {
  test <- d[1]
  if (Find(length, list(grep("/", test), 0)) > 0) {
    return(as.Date(d, "%m/%d/%Y"))
  }

  return(as.Date(d))
}
casact/cascsim documentation built on Nov. 12, 2022, 11:53 p.m.