Lossruns and Triangles

Overview

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.

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:

  • Indemnity
  • Medical
  • Expense

Whereas, in Automobile Insurance Coverages the claim amounts would be split out between

  • Bodily Injury (BI)
  • Property Damage
  • Expense

lossrx supports analysis for the following Property Casualty coverages:

  • Workers Compensation - WC
  • Automobile Liability - AL
  • General Liability - GL
  • Medical Professional Liability - MPL (Hospitals and Physicians)
  • Other Various Liability Types similar to WC, AL, and GL (i.e. property, government, etc.)

Different coverages have different types of fields in their respective lossruns which is discussed in detail in the coverages vignette.

Typical Lossrun Fields

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:

  • Key Fields:
    • Unique Claim ID
    • Occurrence ID (for claims related to a single accident that are grouped by occurrence)
    • Claimant Name (First, Last, etc.)
    • Other Claimant Information (Age, Gender, Tenure, etc.)
    • Policy Details (Retention Limits, Deductibles, Reinsurance Thresholds, Aggregate Thresholds, ALAE Treatment, etc.)
  • Dates
    • Evaluation Date of the Lossrun
    • Date of Accident / Loss
    • Date of Report
    • Report Lag { Report Date - Loss Date } (Calculated)
    • Close Date(s)
    • Re-open Date(s)
    • Hire Date (for employee)
    • Birth Date (for claimant - to derive Age)
  • Claim Information Fields
    • Claim Status
    • Claim Type (Indemnity, Medical Only, Closed no Pay, etc.)
    • Litigation (Boolean)
    • Location (Accident, Claimant, Jurisdiction)
  • Numeric Financial Fields
    • Total Unlimited Reported / Incurred
    • Total Unlimited Paid
    • Total Unlimited Reserve
    • Various Splits depending on Coverage
      • Indemnity, Medical, Expense
      • Bodily Injury, Property Damage, Expense
      • Physician, Hospital, etc.
    • Recoveries, Subrogation, etc.

Example Lossrun

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))

Triangles

Reported Triangle for Worker’s Compensation

Reported Loss Triangle - 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

Paid Loss Triangle - 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

Reported Claim Counts Triangle - 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