diff --git a/R/PIC.R b/R/PIC.R index c798f48..088af82 100644 --- a/R/PIC.R +++ b/R/PIC.R @@ -66,54 +66,36 @@ #' @examples #' PaidIncurredChain(USAApaid, USAAincurred) #' @export -PaidIncurredChain <- function(triangleP,triangleI) { - - # To do list: - # Consider a better function name, change the name in the NAMESPACE file as well - # Consider a better output format, e.g. full triangle, s.e. for all origin periods - # How does the user know if this model is applicable to the data at hand? - # Can the 'for' loops be replaced with apply statments / matrix algebra? - # How do we know the function works? Consider tests, - # e.g. published examples that you can be reproduced - - if(dim(triangleP)[1] != dim(triangleP)[2] || dim(triangleI)[1] != dim(triangleI)[2]) { - stop("Origin and development years should be equal.") +PaidIncurredChain <- function(triangleP, triangleI) { + + triangleP <- checkTriangle(triangleP) + triangleI <- checkTriangle(triangleI) + if (nrow(triangleP) != ncol(triangleP) || nrow(triangleI) != ncol(triangleI)) { + stop("Triangles must be square (same number of origin and development years).") } - if(dim(triangleP)[1] != dim(triangleI)[1]) { - stop("Triangles must have same dimensions.") + if (!identical(dim(triangleP), dim(triangleI))) { + stop("Paid and incurred triangles must have the same dimensions.") } J <- ncol(triangleP) - diagP <- diag(triangleP[J:1, 1:J])[(J-1):1] + diagP <- getLatestCumulative(triangleP)[2:J] # log(P_{i,j}/P_{i,j-1}) triangle - fP <- matrix(data=NA, nrow=J, ncol=J) - for (i in 1:J) { - fP[i, 1] <- log(triangleP[i, 1]) - if (i == J) { - break - } - for (j in 1:(J-i)) { - fP[i, j+1] <- log(triangleP[i, j+1] / triangleP[i, j]) - } - } + logP <- log(triangleP) + fP <- matrix(NA_real_, nrow = J, ncol = J) + fP[, 1] <- logP[, 1] + if (J > 1) fP[, 2:J] <- logP[, 2:J] - logP[, 1:(J-1)] fP <- as.triangle(fP) # log(I_{i,j} / I_{i,j+1}) triangle - fI <- matrix(data=NA, nrow=J, ncol=J) - for (i in 1:(J-1)) { - for (j in 1:(J-i)) { - fI[i, j] <- log(triangleI[i, j] / triangleI[i, j+1]) - } - } + logI <- log(triangleI) + fI <- matrix(NA_real_, nrow = J, ncol = J) + if (J > 1) fI[, 1:(J-1)] <- logI[, 1:(J-1)] - logI[, 2:J] fI <- as.triangle(fI) # sigma_j estimates, j=1,...,J-1 - sigma2.hat <- rep(NA,J) - for (j in 1:(J-1)) { - sigma2.hat[j] <- var(fP[,j], na.rm=T) - } - # sigma_J estimated through log-linear regression + sigma2.hat <- c(apply(fP[, 1:(J-1), drop = FALSE], 2, var, na.rm = TRUE), NA) + # sigma_J estimated through log-linear regression n <- length(sigma2.hat) dev <- 1:n my.dev <- dev[!is.na(sigma2.hat) & sigma2.hat > 0] @@ -121,61 +103,50 @@ PaidIncurredChain <- function(triangleP,triangleI) { sigma2.hat[is.na(sigma2.hat)] <- exp(predict(my.model, newdata=data.frame(my.dev=dev[is.na(sigma2.hat)]))) # tau_j estimates, j=1,...,J-2 - tau2.hat <- rep(NA,J-1) - for (j in 1:(J-2)) { - tau2.hat[j] <- var(fI[,j], na.rm=T) - } - # sigma_{J-1} estimated through log-linear regression + tau2.hat <- c(apply(fI[, 1:(J-2), drop = FALSE], 2, var, na.rm = TRUE), NA) + # tau_{J-1} estimated through log-linear regression n <- length(tau2.hat) dev <- 1:n my.dev <- dev[!is.na(tau2.hat) & tau2.hat > 0] my.model <- lm(log(tau2.hat[my.dev]) ~ my.dev) tau2.hat[is.na(tau2.hat)] <- exp(predict(my.model, newdata=data.frame(my.dev=dev[is.na(tau2.hat)]))) - # v2_j estimates, j=1,...,J - v2 <- rep(NA,J) - for (i in 1:(J-1)) { - v2[i] <- sum(sigma2.hat) + sum(tau2.hat[i:J-1]) - } - v2[J] <- sum(sigma2.hat) - # w2_j estimates, j=1,...,J - w2 <- rep(NA,J) - for (i in 1:J) { - w2[i] <- sum(sigma2.hat[1:i]) - } + w2 <- cumsum(sigma2.hat) + + # v2_j estimates, j=1,...,J (Proposition 2.2 in Merz & Wuthrich 2010) + v2 <- sum(sigma2.hat) + c(rev(cumsum(rev(tau2.hat))), 0) # (c_1,...,c_J,b_1,...,b_{J-1}) parameters - c <- c() - for (j in 1:J) { - if (j==1) { - c[j] <- (1/sigma2.hat[j]) * sum(fP[1:J,j]) - } - else if (j==2) { - c[j] <- (1/sigma2.hat[j]) * sum(fP[1:(J+1-j),j]) + - sum( 1/(v2[1:(j-1)]-w2[1:(j-1)]) * - log(triangleI[J:(J-j+2),1:(j-1)]/triangleP[J:(J-j+2),1:(j-1)])) + c_par <- numeric(J) + for (j in 1:J) { + if (j == 1) { + c_par[j] <- (1/sigma2.hat[j]) * sum(fP[1:J, j]) + } else if (j == 2) { + c_par[j] <- (1/sigma2.hat[j]) * sum(fP[1:(J+1-j), j]) + + sum(1/(v2[1:(j-1)] - w2[1:(j-1)]) * + log(triangleI[J:(J-j+2), 1:(j-1)] / triangleP[J:(J-j+2), 1:(j-1)])) } else { - diag2 <- diag(triangleI[J:(J-j+2),1:(j-1)]) - diag <- diag(triangleP[J:(J-j+2),1:(j-1)]) - c[j] <- (1/sigma2.hat[j]) * sum(fP[1:(J+1-j),j]) + - sum( 1/(v2[1:(j-1)]-w2[1:(j-1)]) * - log(diag2[1:(j-1)]/diag[1:(j-1)])) + diag_I <- diag(triangleI[J:(J-j+2), 1:(j-1)]) + diag_P <- diag(triangleP[J:(J-j+2), 1:(j-1)]) + c_par[j] <- (1/sigma2.hat[j]) * sum(fP[1:(J+1-j), j]) + + sum(1/(v2[1:(j-1)] - w2[1:(j-1)]) * + log(diag_I[1:(j-1)] / diag_P[1:(j-1)])) } } - - b <- c() - for (j in 1:(J-1)) { - if (j==1) { - b[j] <- -(1/tau2.hat[j]) * sum(fI[1:(J-j),j]) - - sum( 1/(v2[1:j]-w2[1:j]) * - log(triangleI[J:(J-j+1),1:j]/triangleP[J:(J-j+1),1:j])) + + b_par <- numeric(J - 1) + for (j in 1:(J-1)) { + if (j == 1) { + b_par[j] <- -(1/tau2.hat[j]) * sum(fI[1:(J-j), j]) - + sum(1/(v2[1:j] - w2[1:j]) * + log(triangleI[J:(J-j+1), 1:j] / triangleP[J:(J-j+1), 1:j])) } else { - diag2 <- diag(triangleI[J:(J-j+1),1:j]) - diag <- diag(triangleP[J:(J-j+1),1:j]) - b[j] <- -(1/tau2.hat[j]) * sum(fI[1:(J-j),j]) - - sum( 1/(v2[1:j]-w2[1:j]) * - log(diag2[1:j]/diag[1:j])) + diag_I <- diag(triangleI[J:(J-j+1), 1:j]) + diag_P <- diag(triangleP[J:(J-j+1), 1:j]) + b_par[j] <- -(1/tau2.hat[j]) * sum(fI[1:(J-j), j]) - + sum(1/(v2[1:j] - w2[1:j]) * + log(diag_I[1:j] / diag_P[1:j])) } } @@ -240,17 +211,17 @@ PaidIncurredChain <- function(triangleP,triangleI) { Ainv <- solve(A) # posterior parameters - cb <- c(c,b) + cb <- c(c_par, b_par) theta.post <- Ainv %*% cb # beta and s2.post parameters - beta <- c() + beta <- numeric(J - 1) for (i in 1:(J-1)) { - beta[i] <- (v2[J] - w2[i])/(v2[i] - w2[i]) + beta[i] <- (v2[J] - w2[i]) / (v2[i] - w2[i]) } - - s2.post <- c() - E <- matrix(NA,nrow=(J-1),ncol=(2*J-1)) + + s2.post <- numeric(J - 1) + E <- matrix(NA_real_, nrow = (J-1), ncol = (2*J-1)) for (i in 2:J) { e <- rep(0,J+1-i) e <- c(e,rep(1 - beta[J+1-i],i-1)) @@ -261,7 +232,7 @@ PaidIncurredChain <- function(triangleP,triangleI) { } # ultimate loss vector - PIC.Ult <- c() + PIC.Ult <- numeric(J - 1) for (i in 2:J) { PIC.Ult[i-1] <- triangleP[i,J+1-i]^(1 - beta[J+1-i]) * triangleI[i,J+1-i]^(beta[J+1-i]) * exp((1 - beta[J+1-i]) * @@ -290,272 +261,11 @@ PaidIncurredChain <- function(triangleP,triangleI) { } PIC.se <- sqrt(msep) - output <- list() - - output[["Ult.Loss.Origin"]] <- as.matrix(PIC.Ult) - output[["Ult.Loss"]] <- as.numeric(PIC.UltTot) - output[["Res.Origin"]] <- as.matrix(PIC.Ris) - output[["Res.Tot"]] <- as.numeric(PIC.RisTot) - output[["s.e."]] <- as.numeric(PIC.se) - - return(output) + list( + Ult.Loss.Origin = as.matrix(PIC.Ult), + Ult.Loss = as.numeric(PIC.UltTot), + Res.Origin = as.matrix(PIC.Ris), + Res.Tot = as.numeric(PIC.RisTot), + s.e. = as.numeric(PIC.se) + ) } - - -# Bayesian model code from Mario Wuthrich -# -# ############################################################# -# ####### functions for parameter initialization -# ############################################################# -# -# param.empirical <- function(xi, I0, J0) { -# param <- array(0, c(J0, 2)) -# for (j in 1:J0){ -# param[j,1] <- mean(xi[(1:(I0-j+1)),j]) -# if (j