A lossrun is an insurance/actuarial term for a dataset containing information about a particular insurance coverage or policy’s individual claims as of a particular point in time known as the evaluation date.
lossrx
provides examples and support functions to aid in
the creation, analysis, validation, and proper storage of actuarial
lossruns specific to P&C Insurance Coverages.
It is important to note the granularity of a particular lossrun with regard to what level of detail its values represent as well as the context in which the data is provided from.
For example, it is common to have separate lossruns by coverage due to the differences in the attributable dimensions associated with the values in those lossruns by coverage.
For example, a Worker’s Compensation lossrun will typically split its values for paid, case reserves, and incurred/reported into lower-level spit-outs by:
Whereas, in Automobile Insurance Coverages the claim amounts would be split out between
lossrx
supports analysis for the following Property
Casualty coverages:
Different coverages have different types of fields in their respective lossruns which is discussed in detail in the coverages vignette.
Each row in a lossrun should correspond to a specific claim at a specific point in time.
The following fields are typical in all lossruns, regardless of coverage of business context:
lossrx
provides example lossruns in the form of a merged
dataset named losses
.
loss_data <- losses
dplyr::glimpse(loss_data)
#> Rows: 79,748
#> Columns: 30
#> $ eval_date <date> 2019-12-31, 2019-08-31, 2019-04-30, 2018-12-31, 20…
#> $ devt_age <dbl> 108, 104, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, …
#> $ occurrence_number <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "…
#> $ coverage <chr> "WC", "WC", "WC", "WC", "WC", "WC", "WC", "WC", "WC…
#> $ member <chr> "Member 2", "Member 2", "Member 2", "Member 2", "Me…
#> $ program_year <chr> "2011", "2011", "2011", "2011", "2011", "2011", "20…
#> $ loss_date <date> 2011-01-03, 2011-01-03, 2011-01-03, 2011-01-03, 20…
#> $ rept_date <date> 2011-01-04, 2011-01-04, 2011-01-04, 2011-01-04, 20…
#> $ hire_date <date> 2000-09-11, 2000-09-11, 2000-09-11, 2000-09-11, 20…
#> $ report_lag <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ report_lag_group <fct> 1 to 3 Days, 1 to 3 Days, 1 to 3 Days, 1 to 3 Days,…
#> $ day_of_week <chr> "Monday", "Monday", "Monday", "Monday", "Monday", "…
#> $ claim_type <chr> "WCIN", "WCIN", "WCIN", "WCIN", "WCIN", "WCIN", "WC…
#> $ claimant_state <chr> "CA", "CA", "CA", "CA", "CA", "CA", "CA", "CA", "CA…
#> $ loss_state <chr> "CA", "CA", "CA", "CA", "CA", "CA", "CA", "CA", "CA…
#> $ cause <chr> "Strain / Overexertion", "Strain / Overexertion", "…
#> $ department <chr> "Drivers", "Drivers", "Drivers", "Drivers", "Driver…
#> $ tenure <dbl> 19.30328, 18.96986, 18.63288, 18.30411, 17.96986, 1…
#> $ tenure_group <fct> 10+ Years, 10+ Years, 10+ Years, 10+ Years, 10+ Yea…
#> $ claimant_age <dbl> 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,…
#> $ claimant_age_group <fct> 30+ Years Old, 30+ Years Old, 30+ Years Old, 30+ Ye…
#> $ driver_age <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
#> $ driver_age_group <fct> (Missing), (Missing), (Missing), (Missing), (Missin…
#> $ status <chr> "C", "C", "C", "C", "C", "C", "C", "C", "C", "C", "…
#> $ total_paid <dbl> 4149.66, 4149.66, 4149.66, 4149.66, 4149.66, 4149.6…
#> $ total_incurred <dbl> 4149.66, 4149.66, 4149.66, 4149.66, 4149.66, 4149.6…
#> $ count <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ open_count <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ close_count <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ incurred_group <fct> $0-$50K, $0-$50K, $0-$50K, $0-$50K, $0-$50K, $0-$50…
Note that the losses
dataset contains
27 unique evaluation dates merged together:
analysis_data_wc <- loss_data |>
filter(coverage == "WC") |>
group_by(.data$eval_date, .data$devt_age, .data$program_year) |>
summarise(
`Total Reported Claim Counts` = n(),
`Total Paid` = sum(.data$total_paid, na.rm = TRUE),
`Total Reported` = sum(.data$total_incurred, na.rm = TRUE)
) |>
ungroup() |>
arrange(program_year, devt_age)
This can easily be translated into triangles like so:
create_triangle <- function(dat, type = c("paid", "reported", "counts")) {
col <- switch(type,
"paid" = "Total Paid",
"reported" = "Total Reported",
"counts" = "Total Reported Claim Counts")
dat |>
dplyr::filter(.data$devt_age %% 12 == 0) |>
dplyr::select(.data$program_year, .data$devt_age, col) |>
tidyr::pivot_wider(
names_from = .data$devt_age,
values_from = col
)
}
wc_tris <- purrr::map(c("Paid Triangle" = "paid",
"Reported Triangle" = "reported",
"Reported Claim Counts Triangle" = "counts"),
~create_triangle(dat = analysis_data_wc, .x))
Reported Triangle for Worker’s Compensation
Program Year | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 |
---|---|---|---|---|---|---|---|---|---|
2011 | $1,848,243 | $2,612,743 | $3,551,146 | $3,984,917 | $4,578,141 | $4,551,360 | $4,668,759 | $4,783,095 | $5,106,152 |
2012 | $1,612,873 | $2,155,524 | $2,724,880 | $3,080,545 | $3,001,161 | $3,165,964 | $3,166,744 | $3,156,258 | NA |
2013 | $2,094,548 | $3,099,719 | $3,740,564 | $4,250,089 | $4,309,443 | $4,260,170 | $4,312,405 | NA | NA |
2014 | $2,261,795 | $3,903,159 | $4,587,802 | $5,255,295 | $5,300,678 | $5,202,209 | NA | NA | NA |
2015 | $2,710,610 | $4,829,110 | $5,336,553 | $5,971,638 | $5,874,727 | NA | NA | NA | NA |
2016 | $2,256,118 | $3,453,264 | $4,597,753 | $4,956,719 | NA | NA | NA | NA | NA |
2017 | $2,968,956 | $4,060,255 | $4,786,980 | NA | NA | NA | NA | NA | NA |
2018 | $3,089,013 | $4,644,813 | NA | NA | NA | NA | NA | NA | NA |
2019 | $3,361,270 | NA | NA | NA | NA | NA | NA | NA | NA |
Paid Triangle for Worker’s Compensation
Program Year | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 |
---|---|---|---|---|---|---|---|---|---|
2011 | $1,038,134 | $1,952,467 | $2,844,909 | $3,206,451 | $3,622,465 | $3,784,433 | $4,391,682 | $4,597,187 | $4,649,071 |
2012 | $964,702 | $1,655,863 | $2,190,679 | $2,696,951 | $2,822,347 | $2,885,805 | $2,907,134 | $2,970,876 | NA |
2013 | $1,099,421 | $2,153,949 | $3,249,769 | $3,870,669 | $4,141,990 | $4,184,586 | $4,238,739 | NA | NA |
2014 | $1,140,280 | $2,961,176 | $3,894,956 | $4,316,046 | $4,609,377 | $4,810,261 | NA | NA | NA |
2015 | $1,498,970 | $3,201,753 | $4,072,723 | $4,945,161 | $5,699,583 | NA | NA | NA | NA |
2016 | $1,201,656 | $2,450,818 | $3,782,187 | $4,662,461 | NA | NA | NA | NA | NA |
2017 | $1,369,660 | $2,853,156 | $3,566,111 | NA | NA | NA | NA | NA | NA |
2018 | $1,680,551 | $3,389,445 | NA | NA | NA | NA | NA | NA | NA |
2019 | $2,088,212 | NA | NA | NA | NA | NA | NA | NA | NA |
Reported Claim Counts Triangle for Worker’s Compensation
Program Year | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 |
---|---|---|---|---|---|---|---|---|---|
2011 | 373 | 376 | 376 | 376 | 376 | 377 | 377 | 377 | 377 |
2012 | 331 | 334 | 335 | 335 | 335 | 335 | 335 | 335 | NA |
2013 | 327 | 330 | 331 | 331 | 331 | 331 | 331 | NA | NA |
2014 | 382 | 391 | 391 | 391 | 391 | 391 | NA | NA | NA |
2015 | 455 | 458 | 458 | 458 | 458 | NA | NA | NA | NA |
2016 | 471 | 477 | 477 | 477 | NA | NA | NA | NA | NA |
2017 | 406 | 413 | 413 | NA | NA | NA | NA | NA | NA |
2018 | 393 | 399 | NA | NA | NA | NA | NA | NA | NA |
2019 | 404 | NA | NA | NA | NA | NA | NA | NA | NA |