diff --git a/docs/friedland/chapter_9.ipynb b/docs/friedland/chapter_9.ipynb index 3665348b..2de0b87d 100644 --- a/docs/friedland/chapter_9.ipynb +++ b/docs/friedland/chapter_9.ipynb @@ -25,9 +25,12 @@ "chapter recreates the Friedland Chapter 9 exhibits, reusing the development\n", "patterns selected in Chapter 7 and the expected claims from Chapter 8:\n", "\n", - "- **Exhibit I** — U.S. Industry Auto\n", - "- **Exhibit II** — XYZ Insurer (Auto BI)\n", - "- **Exhibit III** — U.S. PP Auto (impact of changing conditions)" + "- **Exhibit I** - U.S. Industry Auto\n", + "- **Exhibit II** - XYZ Insurer (Auto BI)\n", + "- **Exhibit III** - U.S. PP Auto (impact of changing conditions)\n", + "- **Exhibit IV** - U.S. Auto (impact of change in product mix)\n", + "- **Exhibit V** - U.S. PP Auto (impact of changing conditions - Gunnar Benktander method)\n", + "- **Exhibit VI** - U.S. Auto (impact of change in product mix - Gunnar Benktander method)\n" ] }, { @@ -36,22 +39,39 @@ "id": "4a72e71f", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:53.216486Z", - "iopub.status.busy": "2026-07-15T04:17:53.215892Z", - "iopub.status.idle": "2026-07-15T04:17:57.268027Z", - "shell.execute_reply": "2026-07-15T04:17:57.267379Z" + "iopub.execute_input": "2026-08-10T06:42:26.899886Z", + "iopub.status.busy": "2026-08-10T06:42:26.899280Z", + "iopub.status.idle": "2026-08-10T06:42:30.130701Z", + "shell.execute_reply": "2026-08-10T06:42:30.129164Z" } }, "outputs": [], "source": [ + "import os\n", "import numpy as np\n", "import pandas as pd\n", "import chainladder as cl\n", - "import os\n", "from IPython.display import display\n", "\n", "pd.set_option(\"display.max_columns\", None)\n", - "pd.set_option(\"display.width\", 1000)" + "pd.set_option(\"display.width\", 1000)\n", + "\n", + "\n", + "def add_total_row(df, sum_cols=None):\n", + " \"\"\"Append a Total row to a DataFrame for display purposes.\"\"\"\n", + " out = df.copy()\n", + " out.index = out.index.astype(str)\n", + " if sum_cols is None:\n", + " non_sum = [\"Age (Months)\", \"CDF Reported\", \"CDF Paid\", \"% Unreported\", \"% Unpaid\"]\n", + " sum_cols = [c for c in out.columns if c not in non_sum]\n", + " total_row = {}\n", + " for col in out.columns:\n", + " if col in sum_cols:\n", + " total_row[col] = out[col].sum()\n", + " else:\n", + " total_row[col] = \"\"\n", + " out.loc[\"Total\"] = total_row\n", + " return out\n" ] }, { @@ -59,7 +79,7 @@ "id": "58740191", "metadata": {}, "source": [ - "## Exhibit I — U.S. Industry Auto\n", + "## Exhibit I - U.S. Industry Auto\n", "\n", "The text works the Bornhuetter-Ferguson method first for **U.S. Industry Auto**\n", "(Exhibit I), valued at 12/31/2007 over accident years 1998-2007. The reporting\n", @@ -80,10 +100,10 @@ "id": "2d99f42f", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:57.275550Z", - "iopub.status.busy": "2026-07-15T04:17:57.273017Z", - "iopub.status.idle": "2026-07-15T04:17:58.117761Z", - "shell.execute_reply": "2026-07-15T04:17:58.116179Z" + "iopub.execute_input": "2026-08-10T06:42:30.137193Z", + "iopub.status.busy": "2026-08-10T06:42:30.134908Z", + "iopub.status.idle": "2026-08-10T06:42:30.725265Z", + "shell.execute_reply": "2026-08-10T06:42:30.723603Z" } }, "outputs": [ @@ -113,8 +133,10 @@ " CDF Paid\n", " % Unreported\n", " % Unpaid\n", - " Reported\n", - " Paid\n", + " Expected Unreported\n", + " Expected Unpaid\n", + " Reported Claims\n", + " Paid Claims\n", " BF Ultimate (Reported)\n", " BF Ultimate (Paid)\n", " \n", @@ -122,140 +144,175 @@ " \n", " \n", " 1998\n", - " 51430657.0\n", - " 1.000\n", + " 51430657\n", + " 1.0\n", " 1.002\n", - " 0.000\n", + " 0.0\n", " 0.002\n", + " 0.0\n", + " 102861.0\n", " 47742304.0\n", " 47644187.0\n", " 47742304.0\n", - " 47746843.0\n", + " 47747048.0\n", " \n", " \n", " 1999\n", - " 51408736.0\n", - " 1.000\n", + " 51408736\n", + " 1.0\n", " 1.004\n", - " 0.000\n", + " 0.0\n", " 0.004\n", + " 0.0\n", + " 205635.0\n", " 51185767.0\n", " 51000534.0\n", " 51185767.0\n", - " 51205554.0\n", + " 51206169.0\n", " \n", " \n", " 2000\n", - " 51680983.0\n", + " 51680983\n", " 1.001\n", " 1.006\n", " 0.001\n", " 0.006\n", + " 51681.0\n", + " 310086.0\n", " 54837929.0\n", " 54533225.0\n", - " 54889558.0\n", - " 54842075.0\n", + " 54889610.0\n", + " 54843311.0\n", " \n", " \n", " 2001\n", - " 54408716.0\n", + " 54408716\n", " 1.003\n", " 1.011\n", " 0.003\n", " 0.011\n", + " 163226.0\n", + " 598496.0\n", " 56299562.0\n", " 55878421.0\n", - " 56462408.0\n", - " 56472644.0\n", + " 56462788.0\n", + " 56476917.0\n", " \n", " \n", " 2002\n", - " 59421665.0\n", + " 59421665\n", " 1.006\n", - " 1.020\n", + " 1.02\n", " 0.006\n", - " 0.020\n", + " 0.02\n", + " 356530.0\n", + " 1188433.0\n", " 58592712.0\n", " 57807215.0\n", - " 58947762.0\n", - " 58980423.0\n", + " 58949242.0\n", + " 58995648.0\n", " \n", " \n", " 2003\n", - " 56318302.0\n", + " 56318302\n", " 1.011\n", - " 1.040\n", + " 1.04\n", " 0.011\n", " 0.038\n", + " 619501.0\n", + " 2140095.0\n", " 57565344.0\n", " 55930654.0\n", - " 58180367.0\n", - " 58071953.0\n", + " 58184845.0\n", + " 58070749.0\n", " \n", " \n", " 2004\n", - " 59646290.0\n", + " 59646290\n", " 1.023\n", " 1.085\n", - " 0.022\n", - " 0.078\n", + " 0.023\n", + " 0.079\n", + " 1371865.0\n", + " 4712057.0\n", " 56976657.0\n", " 53774672.0\n", - " 58327568.0\n", - " 58460755.0\n", + " 58348522.0\n", + " 58486729.0\n", " \n", " \n", " 2005\n", - " 61174953.0\n", + " 61174953\n", " 1.051\n", " 1.184\n", - " 0.049\n", + " 0.048\n", " 0.155\n", + " 2936398.0\n", + " 9482118.0\n", " 56786410.0\n", " 50644994.0\n", - " 59743817.0\n", - " 60152879.0\n", + " 59722808.0\n", + " 60127112.0\n", " \n", " \n", " 2006\n", - " 61926981.0\n", - " 1.110\n", + " 61926981\n", + " 1.11\n", " 1.404\n", " 0.099\n", " 0.288\n", + " 6130771.0\n", + " 17834971.0\n", " 54641339.0\n", " 43606497.0\n", - " 60760348.0\n", - " 61433803.0\n", + " 60772110.0\n", + " 61441468.0\n", " \n", " \n", " 2007\n", - " 61864556.0\n", + " 61864556\n", " 1.292\n", - " 2.390\n", + " 2.39\n", " 0.226\n", " 0.582\n", + " 13981390.0\n", + " 36005172.0\n", " 48853563.0\n", " 27229969.0\n", - " 62821457.0\n", - " 63210141.0\n", + " 62834953.0\n", + " 63235141.0\n", + " \n", + " \n", + " Total\n", + " 569281839\n", + " \n", + " \n", + " \n", + " \n", + " 25611362.0\n", + " 72579924.0\n", + " 543481587.0\n", + " 498050368.0\n", + " 569092949.0\n", + " 570630292.0\n", " \n", " \n", "\n", "" ], "text/plain": [ - " Expected Claims CDF Reported CDF Paid % Unreported % Unpaid Reported Paid BF Ultimate (Reported) BF Ultimate (Paid)\n", - "1998 51430657.0 1.000 1.002 0.000 0.002 47742304.0 47644187.0 47742304.0 47746843.0\n", - "1999 51408736.0 1.000 1.004 0.000 0.004 51185767.0 51000534.0 51185767.0 51205554.0\n", - "2000 51680983.0 1.001 1.006 0.001 0.006 54837929.0 54533225.0 54889558.0 54842075.0\n", - "2001 54408716.0 1.003 1.011 0.003 0.011 56299562.0 55878421.0 56462408.0 56472644.0\n", - "2002 59421665.0 1.006 1.020 0.006 0.020 58592712.0 57807215.0 58947762.0 58980423.0\n", - "2003 56318302.0 1.011 1.040 0.011 0.038 57565344.0 55930654.0 58180367.0 58071953.0\n", - "2004 59646290.0 1.023 1.085 0.022 0.078 56976657.0 53774672.0 58327568.0 58460755.0\n", - "2005 61174953.0 1.051 1.184 0.049 0.155 56786410.0 50644994.0 59743817.0 60152879.0\n", - "2006 61926981.0 1.110 1.404 0.099 0.288 54641339.0 43606497.0 60760348.0 61433803.0\n", - "2007 61864556.0 1.292 2.390 0.226 0.582 48853563.0 27229969.0 62821457.0 63210141.0" + " Expected Claims CDF Reported CDF Paid % Unreported % Unpaid Expected Unreported Expected Unpaid Reported Claims Paid Claims BF Ultimate (Reported) BF Ultimate (Paid)\n", + "1998 51430657 1.0 1.002 0.0 0.002 0.0 102861.0 47742304.0 47644187.0 47742304.0 47747048.0\n", + "1999 51408736 1.0 1.004 0.0 0.004 0.0 205635.0 51185767.0 51000534.0 51185767.0 51206169.0\n", + "2000 51680983 1.001 1.006 0.001 0.006 51681.0 310086.0 54837929.0 54533225.0 54889610.0 54843311.0\n", + "2001 54408716 1.003 1.011 0.003 0.011 163226.0 598496.0 56299562.0 55878421.0 56462788.0 56476917.0\n", + "2002 59421665 1.006 1.02 0.006 0.02 356530.0 1188433.0 58592712.0 57807215.0 58949242.0 58995648.0\n", + "2003 56318302 1.011 1.04 0.011 0.038 619501.0 2140095.0 57565344.0 55930654.0 58184845.0 58070749.0\n", + "2004 59646290 1.023 1.085 0.023 0.079 1371865.0 4712057.0 56976657.0 53774672.0 58348522.0 58486729.0\n", + "2005 61174953 1.051 1.184 0.048 0.155 2936398.0 9482118.0 56786410.0 50644994.0 59722808.0 60127112.0\n", + "2006 61926981 1.11 1.404 0.099 0.288 6130771.0 17834971.0 54641339.0 43606497.0 60772110.0 61441468.0\n", + "2007 61864556 1.292 2.39 0.226 0.582 13981390.0 36005172.0 48853563.0 27229969.0 62834953.0 63235141.0\n", + "Total 569281839 25611362.0 72579924.0 543481587.0 498050368.0 569092949.0 570630292.0" ] }, "metadata": {}, @@ -291,21 +348,41 @@ "ia_rep = cl.model_diagnostics(ia_bf_reported).to_frame(origin_as_datetime=False).T\n", "ia_pd = cl.model_diagnostics(ia_bf_paid).to_frame(origin_as_datetime=False).T\n", "\n", + "ia_rep_latest = ia_rep[\"Latest\"].values\n", + "ia_pd_latest = ia_pd[\"Latest\"].values\n", + "ia_ult_rep = ia_rep[\"Ultimate\"].values\n", + "ia_ult_pd = ia_pd[\"Ultimate\"].values\n", + "\n", "ia_projection = pd.DataFrame(index=ia_years)\n", "ia_projection[\"Expected Claims\"] = ia_expected\n", - "# Derive the percentages from the rounded CDFs so the displayed CDF and\n", - "# percentage columns are internally consistent (as in the text).\n", "ia_cdf_reported = ia_rep[\"CDF\"].round(3)\n", "ia_cdf_paid = ia_pd[\"CDF\"].round(3)\n", "ia_projection[\"CDF Reported\"] = ia_cdf_reported.values\n", "ia_projection[\"CDF Paid\"] = ia_cdf_paid.values\n", "ia_projection[\"% Unreported\"] = (1 - 1 / ia_cdf_reported).round(3).values\n", "ia_projection[\"% Unpaid\"] = (1 - 1 / ia_cdf_paid).round(3).values\n", - "ia_projection[\"Reported\"] = ia_rep[\"Latest\"].values\n", - "ia_projection[\"Paid\"] = ia_pd[\"Latest\"].values\n", - "ia_projection[\"BF Ultimate (Reported)\"] = ia_rep[\"Ultimate\"].round(0).values\n", - "ia_projection[\"BF Ultimate (Paid)\"] = ia_pd[\"Ultimate\"].round(0).values\n", - "display(ia_projection)" + "ia_projection[\"Reported Claims\"] = ia_rep_latest\n", + "ia_projection[\"Paid Claims\"] = ia_pd_latest\n", + "ia_projection[\"BF Ultimate (Reported)\"] = ia_ult_rep.round(0)\n", + "ia_projection[\"BF Ultimate (Paid)\"] = ia_ult_pd.round(0)\n", + "display(add_total_row(ia_projection))\n" + ] + }, + { + "cell_type": "markdown", + "id": "bd4ca9ca", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit I, Sheet 1\n", + "- **(2) Expected Claims**: Developed in Chapter 8, Exhibit II, Sheet 1.\n", + "- **(3) & (4) CDF Reported / Paid**: Developed in Chapter 7, Exhibit I, Sheets 1 & 2.\n", + "- **(5) % Unreported**: $1.00 - (1.00 / (3))$.\n", + "- **(6) % Unpaid**: $1.00 - (1.00 / (4))$.\n", + "- **(7) Expected Unreported**: $(2) \\times (5)$.\n", + "- **(8) Expected Unpaid**: $(2) \\times (6)$.\n", + "- **(9) & (10) Reported / Paid Claims**: Based on data from U.S. Industry Auto.\n", + "- **(11) BF Ultimate (Reported)**: $(7) + (9)$.\n", + "- **(12) BF Ultimate (Paid)**: $(8) + (10)$.\n" ] }, { @@ -326,10 +403,10 @@ "id": "f4b9a268", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:58.121929Z", - "iopub.status.busy": "2026-07-15T04:17:58.121578Z", - "iopub.status.idle": "2026-07-15T04:17:58.168040Z", - "shell.execute_reply": "2026-07-15T04:17:58.166647Z" + "iopub.execute_input": "2026-08-10T06:42:30.729269Z", + "iopub.status.busy": "2026-08-10T06:42:30.728687Z", + "iopub.status.idle": "2026-08-10T06:42:30.758691Z", + "shell.execute_reply": "2026-08-10T06:42:30.757203Z" } }, "outputs": [ @@ -354,6 +431,8 @@ " \n", " \n", " \n", + " Reported Claims\n", + " Paid Claims\n", " BF Ultimate (Reported)\n", " BF Ultimate (Paid)\n", " Case Outstanding\n", @@ -367,119 +446,152 @@ " \n", " 1998\n", " 47742304.0\n", - " 47746843.0\n", + " 47644187.0\n", + " 47742304.0\n", + " 47747048.0\n", " 98117.0\n", " 0.0\n", - " 4539.0\n", + " 4744.0\n", " 98117.0\n", - " 102656.0\n", + " 102861.0\n", " \n", " \n", " 1999\n", " 51185767.0\n", - " 51205554.0\n", + " 51000534.0\n", + " 51185767.0\n", + " 51206169.0\n", " 185233.0\n", " 0.0\n", - " 19787.0\n", + " 20402.0\n", " 185233.0\n", - " 205020.0\n", + " 205635.0\n", " \n", " \n", " 2000\n", - " 54889558.0\n", - " 54842075.0\n", + " 54837929.0\n", + " 54533225.0\n", + " 54889610.0\n", + " 54843311.0\n", " 304704.0\n", - " 51629.0\n", - " 4146.0\n", - " 356333.0\n", - " 308850.0\n", + " 51681.0\n", + " 5382.0\n", + " 356385.0\n", + " 310086.0\n", " \n", " \n", " 2001\n", - " 56462408.0\n", - " 56472644.0\n", + " 56299562.0\n", + " 55878421.0\n", + " 56462788.0\n", + " 56476917.0\n", " 421141.0\n", - " 162846.0\n", - " 173082.0\n", - " 583987.0\n", - " 594223.0\n", + " 163226.0\n", + " 177355.0\n", + " 584367.0\n", + " 598496.0\n", " \n", " \n", " 2002\n", - " 58947762.0\n", - " 58980423.0\n", + " 58592712.0\n", + " 57807215.0\n", + " 58949242.0\n", + " 58995648.0\n", " 785497.0\n", - " 355050.0\n", - " 387711.0\n", - " 1140547.0\n", - " 1173208.0\n", + " 356530.0\n", + " 402936.0\n", + " 1142027.0\n", + " 1188433.0\n", " \n", " \n", " 2003\n", - " 58180367.0\n", - " 58071953.0\n", + " 57565344.0\n", + " 55930654.0\n", + " 58184845.0\n", + " 58070749.0\n", " 1634690.0\n", - " 615023.0\n", - " 506609.0\n", - " 2249713.0\n", - " 2141299.0\n", + " 619501.0\n", + " 505405.0\n", + " 2254191.0\n", + " 2140095.0\n", " \n", " \n", " 2004\n", - " 58327568.0\n", - " 58460755.0\n", + " 56976657.0\n", + " 53774672.0\n", + " 58348522.0\n", + " 58486729.0\n", " 3201985.0\n", - " 1350911.0\n", - " 1484098.0\n", - " 4552896.0\n", - " 4686083.0\n", + " 1371865.0\n", + " 1510072.0\n", + " 4573850.0\n", + " 4712057.0\n", " \n", " \n", " 2005\n", - " 59743817.0\n", - " 60152879.0\n", + " 56786410.0\n", + " 50644994.0\n", + " 59722808.0\n", + " 60127112.0\n", " 6141416.0\n", - " 2957407.0\n", - " 3366469.0\n", - " 9098823.0\n", - " 9507885.0\n", + " 2936398.0\n", + " 3340702.0\n", + " 9077814.0\n", + " 9482118.0\n", " \n", " \n", " 2006\n", - " 60760348.0\n", - " 61433803.0\n", + " 54641339.0\n", + " 43606497.0\n", + " 60772110.0\n", + " 61441468.0\n", " 11034842.0\n", - " 6119009.0\n", - " 6792464.0\n", - " 17153851.0\n", - " 17827306.0\n", + " 6130771.0\n", + " 6800129.0\n", + " 17165613.0\n", + " 17834971.0\n", " \n", " \n", " 2007\n", - " 62821457.0\n", - " 63210141.0\n", + " 48853563.0\n", + " 27229969.0\n", + " 62834953.0\n", + " 63235141.0\n", " 21623594.0\n", - " 13967894.0\n", - " 14356578.0\n", - " 35591488.0\n", - " 35980172.0\n", + " 13981390.0\n", + " 14381578.0\n", + " 35604984.0\n", + " 36005172.0\n", + " \n", + " \n", + " Total\n", + " 543481587.0\n", + " 498050368.0\n", + " 569092949.0\n", + " 570630292.0\n", + " 45431219.0\n", + " 25611362.0\n", + " 27148705.0\n", + " 71042581.0\n", + " 72579924.0\n", " \n", " \n", "\n", "" ], "text/plain": [ - " BF Ultimate (Reported) BF Ultimate (Paid) Case Outstanding IBNR (Reported) IBNR (Paid) Total Unpaid (Reported) Total Unpaid (Paid)\n", - "1998 47742304.0 47746843.0 98117.0 0.0 4539.0 98117.0 102656.0\n", - "1999 51185767.0 51205554.0 185233.0 0.0 19787.0 185233.0 205020.0\n", - "2000 54889558.0 54842075.0 304704.0 51629.0 4146.0 356333.0 308850.0\n", - "2001 56462408.0 56472644.0 421141.0 162846.0 173082.0 583987.0 594223.0\n", - "2002 58947762.0 58980423.0 785497.0 355050.0 387711.0 1140547.0 1173208.0\n", - "2003 58180367.0 58071953.0 1634690.0 615023.0 506609.0 2249713.0 2141299.0\n", - "2004 58327568.0 58460755.0 3201985.0 1350911.0 1484098.0 4552896.0 4686083.0\n", - "2005 59743817.0 60152879.0 6141416.0 2957407.0 3366469.0 9098823.0 9507885.0\n", - "2006 60760348.0 61433803.0 11034842.0 6119009.0 6792464.0 17153851.0 17827306.0\n", - "2007 62821457.0 63210141.0 21623594.0 13967894.0 14356578.0 35591488.0 35980172.0" + " Reported Claims Paid Claims BF Ultimate (Reported) BF Ultimate (Paid) Case Outstanding IBNR (Reported) IBNR (Paid) Total Unpaid (Reported) Total Unpaid (Paid)\n", + "1998 47742304.0 47644187.0 47742304.0 47747048.0 98117.0 0.0 4744.0 98117.0 102861.0\n", + "1999 51185767.0 51000534.0 51185767.0 51206169.0 185233.0 0.0 20402.0 185233.0 205635.0\n", + "2000 54837929.0 54533225.0 54889610.0 54843311.0 304704.0 51681.0 5382.0 356385.0 310086.0\n", + "2001 56299562.0 55878421.0 56462788.0 56476917.0 421141.0 163226.0 177355.0 584367.0 598496.0\n", + "2002 58592712.0 57807215.0 58949242.0 58995648.0 785497.0 356530.0 402936.0 1142027.0 1188433.0\n", + "2003 57565344.0 55930654.0 58184845.0 58070749.0 1634690.0 619501.0 505405.0 2254191.0 2140095.0\n", + "2004 56976657.0 53774672.0 58348522.0 58486729.0 3201985.0 1371865.0 1510072.0 4573850.0 4712057.0\n", + "2005 56786410.0 50644994.0 59722808.0 60127112.0 6141416.0 2936398.0 3340702.0 9077814.0 9482118.0\n", + "2006 54641339.0 43606497.0 60772110.0 61441468.0 11034842.0 6130771.0 6800129.0 17165613.0 17834971.0\n", + "2007 48853563.0 27229969.0 62834953.0 63235141.0 21623594.0 13981390.0 14381578.0 35604984.0 36005172.0\n", + "Total 543481587.0 498050368.0 569092949.0 570630292.0 45431219.0 25611362.0 27148705.0 71042581.0 72579924.0" ] }, "metadata": {}, @@ -488,14 +600,31 @@ ], "source": [ "ia_unpaid = pd.DataFrame(index=ia_years)\n", - "ia_unpaid[\"BF Ultimate (Reported)\"] = ia_rep[\"Ultimate\"].round(0).values\n", - "ia_unpaid[\"BF Ultimate (Paid)\"] = ia_pd[\"Ultimate\"].round(0).values\n", - "ia_unpaid[\"Case Outstanding\"] = (ia_rep[\"Latest\"] - ia_pd[\"Latest\"]).round(0).values\n", - "ia_unpaid[\"IBNR (Reported)\"] = ia_rep[\"IBNR\"].round(0).values\n", - "ia_unpaid[\"IBNR (Paid)\"] = (ia_pd[\"Ultimate\"] - ia_rep[\"Latest\"]).round(0).values\n", - "ia_unpaid[\"Total Unpaid (Reported)\"] = (ia_rep[\"Ultimate\"] - ia_pd[\"Latest\"]).round(0).values\n", - "ia_unpaid[\"Total Unpaid (Paid)\"] = ia_pd[\"IBNR\"].round(0).values\n", - "display(ia_unpaid)" + "ia_unpaid[\"Reported Claims\"] = ia_rep_latest\n", + "ia_unpaid[\"Paid Claims\"] = ia_pd_latest\n", + "ia_unpaid[\"BF Ultimate (Reported)\"] = ia_ult_rep.round(0)\n", + "ia_unpaid[\"BF Ultimate (Paid)\"] = ia_ult_pd.round(0)\n", + "ia_unpaid[\"Case Outstanding\"] = (ia_rep_latest - ia_pd_latest).round(0)\n", + "ia_unpaid[\"IBNR (Reported)\"] = (ia_ult_rep - ia_rep_latest).round(0)\n", + "ia_unpaid[\"IBNR (Paid)\"] = (ia_ult_pd - ia_rep_latest).round(0)\n", + "ia_unpaid[\"Total Unpaid (Reported)\"] = (ia_ult_rep - ia_pd_latest).round(0)\n", + "ia_unpaid[\"Total Unpaid (Paid)\"] = (ia_ult_pd - ia_pd_latest).round(0)\n", + "display(add_total_row(ia_unpaid))" + ] + }, + { + "cell_type": "markdown", + "id": "eb38cbf6", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit I, Sheet 2\n", + "- **(2) & (3) Reported / Paid Claims**: Based on data from U.S. Industry Auto.\n", + "- **(4) & (5) BF Ultimate (Reported / Paid)**: Developed in Exhibit I, Sheet 1.\n", + "- **(6) Case Outstanding**: $(2) - (3)$.\n", + "- **(7) IBNR (Reported)**: $(4) - (2)$.\n", + "- **(8) IBNR (Paid)**: $(5) - (2)$.\n", + "- **(9) Total Unpaid (Reported)**: $(6) + (7) = (4) - (3)$.\n", + "- **(10) Total Unpaid (Paid)**: $(6) + (8) = (5) - (3)$.\n" ] }, { @@ -515,10 +644,10 @@ "id": "64c79fa2", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:58.171738Z", - "iopub.status.busy": "2026-07-15T04:17:58.171341Z", - "iopub.status.idle": "2026-07-15T04:17:58.182778Z", - "shell.execute_reply": "2026-07-15T04:17:58.181879Z" + "iopub.execute_input": "2026-08-10T06:42:30.762141Z", + "iopub.status.busy": "2026-08-10T06:42:30.761780Z", + "iopub.status.idle": "2026-08-10T06:42:30.769118Z", + "shell.execute_reply": "2026-08-10T06:42:30.768330Z" } }, "outputs": [], @@ -529,8 +658,8 @@ "assert np.allclose(ia_projection[\"CDF Paid\"].values,\n", " [1.002, 1.004, 1.006, 1.011, 1.020, 1.040, 1.085, 1.184, 1.404, 2.390], atol=1e-3)\n", "# Exhibit I, Sheet 1 - projected ultimate claims (reconcile within rounding tolerance)\n", - "assert np.isclose(ia_rep[\"Ultimate\"].sum(), 569091348, rtol=5e-3)\n", - "assert np.isclose(ia_pd[\"Ultimate\"].sum(), 570568198, rtol=5e-3)\n", + "assert np.isclose(ia_projection[\"BF Ultimate (Reported)\"].sum(), 569091348, rtol=5e-3)\n", + "assert np.isclose(ia_projection[\"BF Ultimate (Paid)\"].sum(), 570568198, rtol=5e-3)\n", "# Exhibit I, Sheet 2 - estimated IBNR\n", "assert np.isclose(ia_unpaid[\"IBNR (Reported)\"].sum(), 25609761, rtol=5e-3)\n", "assert np.isclose(ia_unpaid[\"IBNR (Paid)\"].sum(), 27086611, rtol=5e-3)" @@ -541,7 +670,7 @@ "id": "1b13e9ad", "metadata": {}, "source": [ - "## Exhibit II — XYZ Insurer (Auto BI)\n", + "## Exhibit II - XYZ Insurer (Auto BI)\n", "\n", "Exhibit II applies the same Bornhuetter-Ferguson method to the **XYZ Insurer -\n", "Auto BI** data, valued at 12/31/2008 over accident years 1998-2008." @@ -552,7 +681,7 @@ "id": "8d5d61e0", "metadata": {}, "source": [ - "## The data\n", + "### The data\n", "\n", "The XYZ Insurer Auto BI reported and paid triangles run from accident year 1998\n", "to 2008. Their most recent diagonal (12/31/2008) is the actual claims the BF\n", @@ -565,10 +694,10 @@ "id": "2cd269eb", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:58.187121Z", - "iopub.status.busy": "2026-07-15T04:17:58.186637Z", - "iopub.status.idle": "2026-07-15T04:17:58.264128Z", - "shell.execute_reply": "2026-07-15T04:17:58.262925Z" + "iopub.execute_input": "2026-08-10T06:42:30.774397Z", + "iopub.status.busy": "2026-08-10T06:42:30.773062Z", + "iopub.status.idle": "2026-08-10T06:42:30.843423Z", + "shell.execute_reply": "2026-08-10T06:42:30.842326Z" } }, "outputs": [ @@ -697,7 +826,7 @@ "id": "e58c06e4", "metadata": {}, "source": [ - "## Development patterns\n", + "### Development patterns\n", "\n", "The BF method reuses the development pattern selected for XYZ in Chapter 7: a\n", "volume-weighted two-period average with a 1.000 reported tail and a 1.010 paid\n", @@ -713,10 +842,10 @@ "id": "0c81b46d", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:58.267719Z", - "iopub.status.busy": "2026-07-15T04:17:58.267369Z", - "iopub.status.idle": "2026-07-15T04:17:58.972705Z", - "shell.execute_reply": "2026-07-15T04:17:58.972023Z" + "iopub.execute_input": "2026-08-10T06:42:30.847873Z", + "iopub.status.busy": "2026-08-10T06:42:30.846856Z", + "iopub.status.idle": "2026-08-10T06:42:31.635225Z", + "shell.execute_reply": "2026-08-10T06:42:31.634256Z" } }, "outputs": [ @@ -883,7 +1012,7 @@ "id": "f7e34483", "metadata": {}, "source": [ - "## Expected claims (a priori)\n", + "### Expected claims (a priori)\n", "\n", "The a priori expected claims come from the expected claims technique (Chapter 8):\n", "earned premium multiplied by a selected claim ratio. The earned premium is now\n", @@ -897,10 +1026,10 @@ "id": "0aa8a19c", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:58.978356Z", - "iopub.status.busy": "2026-07-15T04:17:58.976348Z", - "iopub.status.idle": "2026-07-15T04:17:59.004385Z", - "shell.execute_reply": "2026-07-15T04:17:59.003703Z" + "iopub.execute_input": "2026-08-10T06:42:31.639539Z", + "iopub.status.busy": "2026-08-10T06:42:31.638884Z", + "iopub.status.idle": "2026-08-10T06:42:31.668903Z", + "shell.execute_reply": "2026-08-10T06:42:31.667671Z" } }, "outputs": [ @@ -1049,7 +1178,7 @@ "id": "c683f4d9", "metadata": {}, "source": [ - "## Projection of ultimate claims\n", + "### Projection of ultimate claims\n", "\n", "Applying `BornhuetterFerguson` on both the reported and paid bases produces the\n", "projected ultimate claims. The reported IBNR is floored at zero for the capped\n", @@ -1062,10 +1191,10 @@ "id": "a758ad45", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:59.008039Z", - "iopub.status.busy": "2026-07-15T04:17:59.007693Z", - "iopub.status.idle": "2026-07-15T04:17:59.156134Z", - "shell.execute_reply": "2026-07-15T04:17:59.154874Z" + "iopub.execute_input": "2026-08-10T06:42:31.672802Z", + "iopub.status.busy": "2026-08-10T06:42:31.672210Z", + "iopub.status.idle": "2026-08-10T06:42:31.793486Z", + "shell.execute_reply": "2026-08-10T06:42:31.791088Z" } }, "outputs": [ @@ -1090,14 +1219,15 @@ " \n", " \n", " \n", - " Reported\n", - " Paid\n", + " Expected Claims\n", " CDF Reported\n", " CDF Paid\n", " % Unreported\n", " % Unpaid\n", - " Earned Premium\n", - " Expected Claims\n", + " Expected Unreported\n", + " Expected Unpaid\n", + " Reported Claims\n", + " Paid Claims\n", " BF Ultimate (Reported)\n", " BF Ultimate (Paid)\n", " \n", @@ -1105,164 +1235,190 @@ " \n", " \n", " 1998\n", + " 15670\n", + " 1.0\n", + " 1.01\n", + " 0.0\n", + " 0.01\n", + " 0.0\n", + " 155.0\n", " 15822.0\n", " 15822.0\n", - " 1.000\n", - " 1.010\n", - " 0.000\n", - " 0.010\n", - " 20000.0\n", - " 15670\n", " 15822.0\n", " 15977.0\n", " \n", " \n", " 1999\n", - " 25107.0\n", - " 24817.0\n", - " 1.000\n", + " 24680\n", + " 1.0\n", " 1.014\n", - " 0.000\n", + " 0.0\n", " 0.014\n", - " 31500.0\n", - " 24680\n", + " 0.0\n", + " 342.0\n", + " 25107.0\n", + " 24817.0\n", " 25107.0\n", " 25159.0\n", " \n", " \n", " 2000\n", + " 35256\n", + " 1.0\n", + " 1.031\n", + " 0.0\n", + " 0.03\n", + " 0.0\n", + " 1069.0\n", " 37246.0\n", " 36782.0\n", - " 1.000\n", - " 1.031\n", - " 0.000\n", - " 0.030\n", - " 45000.0\n", - " 35256\n", " 37246.0\n", " 37851.0\n", " \n", " \n", " 2001\n", - " 38798.0\n", - " 38519.0\n", - " 1.000\n", + " 39174\n", + " 1.0\n", " 1.054\n", - " 0.000\n", + " 0.0\n", " 0.051\n", - " 50000.0\n", - " 39174\n", + " 0.0\n", + " 2006.0\n", + " 38798.0\n", + " 38519.0\n", " 38798.0\n", " 40525.0\n", " \n", " \n", " 2002\n", - " 48169.0\n", - " 44437.0\n", + " 47935\n", " 1.003\n", " 1.116\n", " 0.003\n", " 0.104\n", - " 61183.0\n", - " 47935\n", + " 140.0\n", + " 4988.0\n", + " 48169.0\n", + " 44437.0\n", " 48309.0\n", " 49425.0\n", " \n", " \n", " 2003\n", - " 44373.0\n", - " 39320.0\n", + " 54197\n", " 1.013\n", " 1.268\n", " 0.013\n", " 0.211\n", - " 69175.0\n", - " 54197\n", + " 693.0\n", + " 11453.0\n", + " 44373.0\n", + " 39320.0\n", " 45066.0\n", " 50773.0\n", " \n", " \n", " 2004\n", - " 70288.0\n", - " 52811.0\n", + " 86528\n", " 1.064\n", " 1.525\n", - " 0.060\n", + " 0.06\n", " 0.344\n", - " 99322.0\n", - " 86528\n", + " 5174.0\n", + " 29801.0\n", + " 70288.0\n", + " 52811.0\n", " 75462.0\n", " 82612.0\n", " \n", " \n", " 2005\n", - " 70655.0\n", - " 40026.0\n", + " 108241\n", " 1.085\n", " 2.007\n", " 0.078\n", " 0.502\n", - " 138151.0\n", - " 108241\n", + " 8468.0\n", + " 54319.0\n", + " 70655.0\n", + " 40026.0\n", " 79123.0\n", " 94345.0\n", " \n", " \n", " 2006\n", - " 48804.0\n", - " 22819.0\n", + " 70769\n", " 1.196\n", - " 3.160\n", + " 3.16\n", " 0.164\n", " 0.684\n", - " 107578.0\n", - " 70769\n", + " 11574.0\n", + " 48371.0\n", + " 48804.0\n", + " 22819.0\n", " 60378.0\n", " 71190.0\n", " \n", " \n", " 2007\n", - " 31732.0\n", - " 11865.0\n", + " 39841\n", " 1.512\n", " 6.569\n", " 0.339\n", " 0.848\n", - " 62438.0\n", - " 39841\n", + " 13497.0\n", + " 33776.0\n", + " 31732.0\n", + " 11865.0\n", " 45229.0\n", " 45641.0\n", " \n", " \n", " 2008\n", - " 18632.0\n", - " 3409.0\n", + " 39429\n", " 2.551\n", " 21.999\n", " 0.608\n", " 0.955\n", - " 47797.0\n", - " 39429\n", + " 23975.0\n", + " 37637.0\n", + " 18632.0\n", + " 3409.0\n", " 42607.0\n", " 41046.0\n", " \n", + " \n", + " Total\n", + " 561720\n", + " \n", + " \n", + " \n", + " \n", + " 63521.0\n", + " 223917.0\n", + " 449626.0\n", + " 330627.0\n", + " 513147.0\n", + " 554544.0\n", + " \n", " \n", "\n", "" ], "text/plain": [ - " Reported Paid CDF Reported CDF Paid % Unreported % Unpaid Earned Premium Expected Claims BF Ultimate (Reported) BF Ultimate (Paid)\n", - "1998 15822.0 15822.0 1.000 1.010 0.000 0.010 20000.0 15670 15822.0 15977.0\n", - "1999 25107.0 24817.0 1.000 1.014 0.000 0.014 31500.0 24680 25107.0 25159.0\n", - "2000 37246.0 36782.0 1.000 1.031 0.000 0.030 45000.0 35256 37246.0 37851.0\n", - "2001 38798.0 38519.0 1.000 1.054 0.000 0.051 50000.0 39174 38798.0 40525.0\n", - "2002 48169.0 44437.0 1.003 1.116 0.003 0.104 61183.0 47935 48309.0 49425.0\n", - "2003 44373.0 39320.0 1.013 1.268 0.013 0.211 69175.0 54197 45066.0 50773.0\n", - "2004 70288.0 52811.0 1.064 1.525 0.060 0.344 99322.0 86528 75462.0 82612.0\n", - "2005 70655.0 40026.0 1.085 2.007 0.078 0.502 138151.0 108241 79123.0 94345.0\n", - "2006 48804.0 22819.0 1.196 3.160 0.164 0.684 107578.0 70769 60378.0 71190.0\n", - "2007 31732.0 11865.0 1.512 6.569 0.339 0.848 62438.0 39841 45229.0 45641.0\n", - "2008 18632.0 3409.0 2.551 21.999 0.608 0.955 47797.0 39429 42607.0 41046.0" + " Expected Claims CDF Reported CDF Paid % Unreported % Unpaid Expected Unreported Expected Unpaid Reported Claims Paid Claims BF Ultimate (Reported) BF Ultimate (Paid)\n", + "1998 15670 1.0 1.01 0.0 0.01 0.0 155.0 15822.0 15822.0 15822.0 15977.0\n", + "1999 24680 1.0 1.014 0.0 0.014 0.0 342.0 25107.0 24817.0 25107.0 25159.0\n", + "2000 35256 1.0 1.031 0.0 0.03 0.0 1069.0 37246.0 36782.0 37246.0 37851.0\n", + "2001 39174 1.0 1.054 0.0 0.051 0.0 2006.0 38798.0 38519.0 38798.0 40525.0\n", + "2002 47935 1.003 1.116 0.003 0.104 140.0 4988.0 48169.0 44437.0 48309.0 49425.0\n", + "2003 54197 1.013 1.268 0.013 0.211 693.0 11453.0 44373.0 39320.0 45066.0 50773.0\n", + "2004 86528 1.064 1.525 0.06 0.344 5174.0 29801.0 70288.0 52811.0 75462.0 82612.0\n", + "2005 108241 1.085 2.007 0.078 0.502 8468.0 54319.0 70655.0 40026.0 79123.0 94345.0\n", + "2006 70769 1.196 3.16 0.164 0.684 11574.0 48371.0 48804.0 22819.0 60378.0 71190.0\n", + "2007 39841 1.512 6.569 0.339 0.848 13497.0 33776.0 31732.0 11865.0 45229.0 45641.0\n", + "2008 39429 2.551 21.999 0.608 0.955 23975.0 37637.0 18632.0 3409.0 42607.0 41046.0\n", + "Total 561720 63521.0 223917.0 449626.0 330627.0 513147.0 554544.0" ] }, "metadata": {}, @@ -1277,18 +1433,39 @@ "reported_ult = reported_latest + reported_ibnr\n", "paid_ult = col(bf_paid.ultimate_)\n", "\n", + "exp_unrep_xyz = np.round(np.array(expected_claims) * pct_unreported)\n", + "exp_unpaid_xyz = np.round(np.array(expected_claims) * pct_unpaid)\n", + "\n", "projection = pd.DataFrame(index=years)\n", - "projection[\"Reported\"] = reported_latest\n", - "projection[\"Paid\"] = paid_latest\n", + "projection[\"Expected Claims\"] = expected_claims\n", "projection[\"CDF Reported\"] = reported_cdf.round(3)\n", "projection[\"CDF Paid\"] = paid_cdf.round(3)\n", "projection[\"% Unreported\"] = pct_unreported.round(3)\n", "projection[\"% Unpaid\"] = pct_unpaid.round(3)\n", - "projection[\"Earned Premium\"] = earned_premium\n", - "projection[\"Expected Claims\"] = expected_claims\n", + "projection[\"Expected Unreported\"] = exp_unrep_xyz\n", + "projection[\"Expected Unpaid\"] = exp_unpaid_xyz\n", + "projection[\"Reported Claims\"] = reported_latest\n", + "projection[\"Paid Claims\"] = paid_latest\n", "projection[\"BF Ultimate (Reported)\"] = reported_ult.round(0)\n", "projection[\"BF Ultimate (Paid)\"] = paid_ult.round(0)\n", - "display(projection)" + "display(add_total_row(projection))" + ] + }, + { + "cell_type": "markdown", + "id": "6c60387e", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit II, Sheet 1\n", + "- **(2) Expected Claims**: Developed in Chapter 8, Exhibit III, Sheet 1.\n", + "- **(3) & (4) CDF Reported / Paid**: Developed in Chapter 7, Exhibit II, Sheets 1 & 2 (capped at 1.000 minimum).\n", + "- **(5) % Unreported**: $1.00 - (1.00 / (3))$.\n", + "- **(6) % Unpaid**: $1.00 - (1.00 / (4))$.\n", + "- **(7) Expected Unreported**: $(2) \\times (5)$.\n", + "- **(8) Expected Unpaid**: $(2) \\times (6)$.\n", + "- **(9) & (10) Reported / Paid Claims**: Based on data from XYZ Insurer.\n", + "- **(11) BF Ultimate (Reported)**: $(7) + (9)$.\n", + "- **(12) BF Ultimate (Paid)**: $(8) + (10)$.\n" ] }, { @@ -1296,7 +1473,7 @@ "id": "db8655a7", "metadata": {}, "source": [ - "## Development of unpaid claim estimate\n", + "### Development of unpaid claim estimate\n", "\n", "From the projected ultimates, the IBNR and total unpaid estimates follow by\n", "simple differences: IBNR is ultimate minus reported claims, and total unpaid is\n", @@ -1309,10 +1486,10 @@ "id": "7ced2979", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:59.159708Z", - "iopub.status.busy": "2026-07-15T04:17:59.159264Z", - "iopub.status.idle": "2026-07-15T04:17:59.187779Z", - "shell.execute_reply": "2026-07-15T04:17:59.187158Z" + "iopub.execute_input": "2026-08-10T06:42:31.797843Z", + "iopub.status.busy": "2026-08-10T06:42:31.797431Z", + "iopub.status.idle": "2026-08-10T06:42:31.823963Z", + "shell.execute_reply": "2026-08-10T06:42:31.823411Z" } }, "outputs": [ @@ -1337,6 +1514,8 @@ " \n", " \n", " \n", + " Reported Claims\n", + " Paid Claims\n", " BF Ultimate (Reported)\n", " BF Ultimate (Paid)\n", " Case Outstanding\n", @@ -1350,6 +1529,8 @@ " \n", " 1998\n", " 15822.0\n", + " 15822.0\n", + " 15822.0\n", " 15977.0\n", " 0.0\n", " 0.0\n", @@ -1360,6 +1541,8 @@ " \n", " 1999\n", " 25107.0\n", + " 24817.0\n", + " 25107.0\n", " 25159.0\n", " 290.0\n", " 0.0\n", @@ -1370,6 +1553,8 @@ " \n", " 2000\n", " 37246.0\n", + " 36782.0\n", + " 37246.0\n", " 37851.0\n", " 464.0\n", " 0.0\n", @@ -1380,6 +1565,8 @@ " \n", " 2001\n", " 38798.0\n", + " 38519.0\n", + " 38798.0\n", " 40525.0\n", " 279.0\n", " 0.0\n", @@ -1389,6 +1576,8 @@ " \n", " \n", " 2002\n", + " 48169.0\n", + " 44437.0\n", " 48309.0\n", " 49425.0\n", " 3732.0\n", @@ -1399,6 +1588,8 @@ " \n", " \n", " 2003\n", + " 44373.0\n", + " 39320.0\n", " 45066.0\n", " 50773.0\n", " 5053.0\n", @@ -1409,6 +1600,8 @@ " \n", " \n", " 2004\n", + " 70288.0\n", + " 52811.0\n", " 75462.0\n", " 82612.0\n", " 17477.0\n", @@ -1419,6 +1612,8 @@ " \n", " \n", " 2005\n", + " 70655.0\n", + " 40026.0\n", " 79123.0\n", " 94345.0\n", " 30629.0\n", @@ -1429,6 +1624,8 @@ " \n", " \n", " 2006\n", + " 48804.0\n", + " 22819.0\n", " 60378.0\n", " 71190.0\n", " 25985.0\n", @@ -1439,6 +1636,8 @@ " \n", " \n", " 2007\n", + " 31732.0\n", + " 11865.0\n", " 45229.0\n", " 45641.0\n", " 19867.0\n", @@ -1449,6 +1648,8 @@ " \n", " \n", " 2008\n", + " 18632.0\n", + " 3409.0\n", " 42607.0\n", " 41046.0\n", " 15223.0\n", @@ -1457,23 +1658,36 @@ " 39198.0\n", " 37637.0\n", " \n", + " \n", + " Total\n", + " 449626.0\n", + " 330627.0\n", + " 513147.0\n", + " 554544.0\n", + " 118999.0\n", + " 63521.0\n", + " 104918.0\n", + " 182520.0\n", + " 223917.0\n", + " \n", " \n", "\n", "" ], "text/plain": [ - " BF Ultimate (Reported) BF Ultimate (Paid) Case Outstanding IBNR (Reported) IBNR (Paid) Total Unpaid (Reported) Total Unpaid (Paid)\n", - "1998 15822.0 15977.0 0.0 0.0 155.0 0.0 155.0\n", - "1999 25107.0 25159.0 290.0 0.0 52.0 290.0 342.0\n", - "2000 37246.0 37851.0 464.0 0.0 605.0 464.0 1069.0\n", - "2001 38798.0 40525.0 279.0 0.0 1727.0 279.0 2006.0\n", - "2002 48309.0 49425.0 3732.0 140.0 1256.0 3872.0 4988.0\n", - "2003 45066.0 50773.0 5053.0 693.0 6400.0 5746.0 11453.0\n", - "2004 75462.0 82612.0 17477.0 5174.0 12324.0 22651.0 29801.0\n", - "2005 79123.0 94345.0 30629.0 8468.0 23690.0 39097.0 54319.0\n", - "2006 60378.0 71190.0 25985.0 11574.0 22386.0 37559.0 48371.0\n", - "2007 45229.0 45641.0 19867.0 13497.0 13909.0 33364.0 33776.0\n", - "2008 42607.0 41046.0 15223.0 23975.0 22414.0 39198.0 37637.0" + " Reported Claims Paid Claims BF Ultimate (Reported) BF Ultimate (Paid) Case Outstanding IBNR (Reported) IBNR (Paid) Total Unpaid (Reported) Total Unpaid (Paid)\n", + "1998 15822.0 15822.0 15822.0 15977.0 0.0 0.0 155.0 0.0 155.0\n", + "1999 25107.0 24817.0 25107.0 25159.0 290.0 0.0 52.0 290.0 342.0\n", + "2000 37246.0 36782.0 37246.0 37851.0 464.0 0.0 605.0 464.0 1069.0\n", + "2001 38798.0 38519.0 38798.0 40525.0 279.0 0.0 1727.0 279.0 2006.0\n", + "2002 48169.0 44437.0 48309.0 49425.0 3732.0 140.0 1256.0 3872.0 4988.0\n", + "2003 44373.0 39320.0 45066.0 50773.0 5053.0 693.0 6400.0 5746.0 11453.0\n", + "2004 70288.0 52811.0 75462.0 82612.0 17477.0 5174.0 12324.0 22651.0 29801.0\n", + "2005 70655.0 40026.0 79123.0 94345.0 30629.0 8468.0 23690.0 39097.0 54319.0\n", + "2006 48804.0 22819.0 60378.0 71190.0 25985.0 11574.0 22386.0 37559.0 48371.0\n", + "2007 31732.0 11865.0 45229.0 45641.0 19867.0 13497.0 13909.0 33364.0 33776.0\n", + "2008 18632.0 3409.0 42607.0 41046.0 15223.0 23975.0 22414.0 39198.0 37637.0\n", + "Total 449626.0 330627.0 513147.0 554544.0 118999.0 63521.0 104918.0 182520.0 223917.0" ] }, "metadata": {}, @@ -1482,6 +1696,8 @@ ], "source": [ "unpaid = pd.DataFrame(index=years)\n", + "unpaid[\"Reported Claims\"] = reported_latest\n", + "unpaid[\"Paid Claims\"] = paid_latest\n", "unpaid[\"BF Ultimate (Reported)\"] = reported_ult.round(0)\n", "unpaid[\"BF Ultimate (Paid)\"] = paid_ult.round(0)\n", "unpaid[\"Case Outstanding\"] = (reported_latest - paid_latest).round(0)\n", @@ -1489,101 +1705,48 @@ "unpaid[\"IBNR (Paid)\"] = (paid_ult - reported_latest).round(0)\n", "unpaid[\"Total Unpaid (Reported)\"] = (reported_ult - paid_latest).round(0)\n", "unpaid[\"Total Unpaid (Paid)\"] = (paid_ult - paid_latest).round(0)\n", - "display(unpaid)" + "display(add_total_row(unpaid))" ] }, { "cell_type": "markdown", - "id": "b135b0ef", + "id": "3ed77340", "metadata": {}, "source": [ - "## Reconciliation to Friedland\n", - "\n", - "The selected CDFs, the projected ultimate claims, and the IBNR estimates are\n", - "reconciled to the printed Chapter 9 exhibit below (values in $000)." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "7ee5e130", - "metadata": { - "execution": { - "iopub.execute_input": "2026-07-15T04:17:59.190099Z", - "iopub.status.busy": "2026-07-15T04:17:59.189820Z", - "iopub.status.idle": "2026-07-15T04:17:59.200373Z", - "shell.execute_reply": "2026-07-15T04:17:59.199165Z" - } - }, - "outputs": [], - "source": [ - "# Selected CDFs to ultimate\n", - "assert np.allclose(reported_cdf.round(3),\n", - " [1.000, 1.000, 1.000, 1.000, 1.003, 1.013, 1.064, 1.085, 1.196, 1.512, 2.551], atol=1e-3)\n", - "assert np.allclose(paid_cdf.round(3),\n", - " [1.010, 1.014, 1.031, 1.054, 1.116, 1.268, 1.525, 2.007, 3.160, 6.569, 21.999], atol=1e-3)\n", - "# Projected ultimate claims\n", - "assert np.allclose(reported_ult,\n", - " [15822, 25107, 37246, 38798, 48309, 45066, 75462, 79123, 60378, 45229, 42607], atol=1)\n", - "assert np.allclose(paid_ult,\n", - " [15977, 25159, 37851, 40525, 49425, 50773, 82612, 94345, 71190, 45641, 41046], atol=1)\n", - "# IBNR (ultimate minus reported)\n", - "assert np.allclose(unpaid[\"IBNR (Reported)\"].values,\n", - " [0, 0, 0, 0, 140, 693, 5174, 8468, 11574, 13497, 23975], atol=1)\n", - "assert np.allclose(unpaid[\"IBNR (Paid)\"].values,\n", - " [155, 52, 605, 1727, 1256, 6400, 12324, 23690, 22386, 13909, 22414], atol=1)" + "### Column Notes - Exhibit II, Sheet 2\n", + "- **(2) & (3) Reported / Paid Claims**: Based on data from XYZ Insurer.\n", + "- **(4) & (5) BF Ultimate (Reported / Paid)**: Developed in Exhibit II, Sheet 1.\n", + "- **(6) Case Outstanding**: $(2) - (3)$.\n", + "- **(7) IBNR (Reported)**: $(4) - (2)$.\n", + "- **(8) IBNR (Paid)**: $(5) - (2)$.\n", + "- **(9) Total Unpaid (Reported)**: $(6) + (7) = (4) - (3)$.\n", + "- **(10) Total Unpaid (Paid)**: $(6) + (8) = (5) - (3)$.\n" ] }, { "cell_type": "markdown", - "id": "c28f0940", + "id": "ex2_summary_md", "metadata": {}, "source": [ - "## Exhibit III — U.S. PP Auto (Impact of Changing Conditions)\n", - "\n", - "Exhibit III applies the Bornhuetter-Ferguson method to the four **U.S. PP Auto**\n", - "scenarios that Friedland uses to study a changing environment (valued at\n", - "12/31/2008, accident years 1999-2008):\n", - "\n", - "1. Steady-State\n", - "2. Increasing Claim Ratios\n", - "3. Increasing Case Outstanding Strength\n", - "4. Increasing Claim Ratios and Case Outstanding Strength\n", + "### Summary of ultimate claims and IBNR\n", "\n", - "All four scenarios share the same a priori expected claims (a 70% expected claim\n", - "ratio applied to earned premium, from Chapter 8) and the same five-year simple\n", - "average development selection from Chapter 7. Because Friedland rounds both the\n", - "cumulative development factors and the resulting percentages, we fold the rounded\n", - "percentages into an effective CDF so `BornhuetterFerguson` reproduces the text.\n", - "\n", - "> **Note on sample data.** The reported figures for the two *case outstanding\n", - "> strength* scenarios do not yet reconcile exactly. The reported development in\n", - "> the `friedland_uspp_auto_increasing_case` and `friedland_uspp_increasing_claim_case`\n", - "> samples differs slightly from the text (a known data correction to these CSVs\n", - "> is still outstanding), so the reconciliation below asserts the reported basis\n", - "> only for the two scenarios with clean data, and the paid basis for all four." + "This recreates *Exhibit II, Sheet 3* (summary of ultimate claims across methods)\n", + "and *Exhibit II, Sheet 4* (summary of estimated IBNR across methods)." ] }, { "cell_type": "code", - "execution_count": 11, - "id": "9f35cbe8", + "execution_count": 10, + "id": "ex2_summary_code", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:17:59.203677Z", - "iopub.status.busy": "2026-07-15T04:17:59.203414Z", - "iopub.status.idle": "2026-07-15T04:18:00.615179Z", - "shell.execute_reply": "2026-07-15T04:18:00.614296Z" + "iopub.execute_input": "2026-08-10T06:42:31.829732Z", + "iopub.status.busy": "2026-08-10T06:42:31.829441Z", + "iopub.status.idle": "2026-08-10T06:42:31.890917Z", + "shell.execute_reply": "2026-08-10T06:42:31.890376Z" } }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Steady-State\n" - ] - }, { "data": { "text/html": [ @@ -1605,96 +1768,3321 @@ " \n", " \n", " \n", + " Reported Claims\n", + " Paid Claims\n", + " Dev Method (Reported)\n", + " Dev Method (Paid)\n", " Expected Claims\n", - " Reported\n", - " Paid\n", + " BF Method (Reported)\n", + " BF Method (Paid)\n", + " \n", + " \n", + " \n", + " \n", + " 1998\n", + " 15822.0\n", + " 15822.0\n", + " 15822.0\n", + " 15980.0\n", + " 15670\n", + " 15822.0\n", + " 15977.0\n", + " \n", + " \n", + " 1999\n", + " 25107.0\n", + " 24817.0\n", + " 25082.0\n", + " 25165.0\n", + " 24680\n", + " 25107.0\n", + " 25159.0\n", + " \n", + " \n", + " 2000\n", + " 37246.0\n", + " 36782.0\n", + " 36948.0\n", + " 37932.0\n", + " 35256\n", + " 37246.0\n", + " 37851.0\n", + " \n", + " \n", + " 2001\n", + " 38798.0\n", + " 38519.0\n", + " 38488.0\n", + " 40598.0\n", + " 39174\n", + " 38798.0\n", + " 40525.0\n", + " \n", + " \n", + " 2002\n", + " 48169.0\n", + " 44437.0\n", + " 48310.0\n", + " 49598.0\n", + " 47935\n", + " 48309.0\n", + " 49425.0\n", + " \n", + " \n", + " 2003\n", + " 44373.0\n", + " 39320.0\n", + " 44948.0\n", + " 49856.0\n", + " 54197\n", + " 45066.0\n", + " 50773.0\n", + " \n", + " \n", + " 2004\n", + " 70288.0\n", + " 52811.0\n", + " 74758.0\n", + " 80555.0\n", + " 86528\n", + " 75462.0\n", + " 82612.0\n", + " \n", + " \n", + " 2005\n", + " 70655.0\n", + " 40026.0\n", + " 76651.0\n", + " 80346.0\n", + " 108241\n", + " 79123.0\n", + " 94345.0\n", + " \n", + " \n", + " 2006\n", + " 48804.0\n", + " 22819.0\n", + " 58346.0\n", + " 72098.0\n", + " 70769\n", + " 60378.0\n", + " 71190.0\n", + " \n", + " \n", + " 2007\n", + " 31732.0\n", + " 11865.0\n", + " 47990.0\n", + " 77938.0\n", + " 39841\n", + " 45229.0\n", + " 45641.0\n", + " \n", + " \n", + " 2008\n", + " 18632.0\n", + " 3409.0\n", + " 47536.0\n", + " 74994.0\n", + " 39429\n", + " 42607.0\n", + " 41046.0\n", + " \n", + " \n", + " Total\n", + " 449626.0\n", + " 330627.0\n", + " 514879.0\n", + " 605060.0\n", + " 561720\n", + " 513147.0\n", + " 554544.0\n", + " \n", + " \n", + "\n", + "" + ], + "text/plain": [ + " Reported Claims Paid Claims Dev Method (Reported) Dev Method (Paid) Expected Claims BF Method (Reported) BF Method (Paid)\n", + "1998 15822.0 15822.0 15822.0 15980.0 15670 15822.0 15977.0\n", + "1999 25107.0 24817.0 25082.0 25165.0 24680 25107.0 25159.0\n", + "2000 37246.0 36782.0 36948.0 37932.0 35256 37246.0 37851.0\n", + "2001 38798.0 38519.0 38488.0 40598.0 39174 38798.0 40525.0\n", + "2002 48169.0 44437.0 48310.0 49598.0 47935 48309.0 49425.0\n", + "2003 44373.0 39320.0 44948.0 49856.0 54197 45066.0 50773.0\n", + "2004 70288.0 52811.0 74758.0 80555.0 86528 75462.0 82612.0\n", + "2005 70655.0 40026.0 76651.0 80346.0 108241 79123.0 94345.0\n", + "2006 48804.0 22819.0 58346.0 72098.0 70769 60378.0 71190.0\n", + "2007 31732.0 11865.0 47990.0 77938.0 39841 45229.0 45641.0\n", + "2008 18632.0 3409.0 47536.0 74994.0 39429 42607.0 41046.0\n", + "Total 449626.0 330627.0 514879.0 605060.0 561720 513147.0 554544.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Case OutstandingDev Method (Reported)Dev Method (Paid)Expected ClaimsBF Method (Reported)BF Method (Paid)
19980.00.0158.0-152.00.0155.0
1999290.0-25.058.0-427.00.052.0
2000464.0-298.0686.0-1990.00.0605.0
2001279.0-310.01800.0376.00.01727.0
20023732.0141.01429.0-234.0140.01256.0
20035053.0575.05483.09824.0693.06400.0
200417477.04470.010267.016240.05174.012324.0
200530629.05996.09691.037586.08468.023690.0
200625985.09542.023294.021965.011574.022386.0
200719867.016258.046206.08109.013497.013909.0
200815223.028904.056362.020797.023975.022414.0
Total118999.065253.0155434.0112094.063521.0104918.0
\n", + "
" + ], + "text/plain": [ + " Case Outstanding Dev Method (Reported) Dev Method (Paid) Expected Claims BF Method (Reported) BF Method (Paid)\n", + "1998 0.0 0.0 158.0 -152.0 0.0 155.0\n", + "1999 290.0 -25.0 58.0 -427.0 0.0 52.0\n", + "2000 464.0 -298.0 686.0 -1990.0 0.0 605.0\n", + "2001 279.0 -310.0 1800.0 376.0 0.0 1727.0\n", + "2002 3732.0 141.0 1429.0 -234.0 140.0 1256.0\n", + "2003 5053.0 575.0 5483.0 9824.0 693.0 6400.0\n", + "2004 17477.0 4470.0 10267.0 16240.0 5174.0 12324.0\n", + "2005 30629.0 5996.0 9691.0 37586.0 8468.0 23690.0\n", + "2006 25985.0 9542.0 23294.0 21965.0 11574.0 22386.0\n", + "2007 19867.0 16258.0 46206.0 8109.0 13497.0 13909.0\n", + "2008 15223.0 28904.0 56362.0 20797.0 23975.0 22414.0\n", + "Total 118999.0 65253.0 155434.0 112094.0 63521.0 104918.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cl_rep = cl.Chainladder().fit(reported_dev)\n", + "cl_pd = cl.Chainladder().fit(paid_dev)\n", + "dev_ult_rep = np.round(col(cl_rep.ultimate_))\n", + "dev_ult_pd = np.round(col(cl_pd.ultimate_))\n", + "dev_ibnr_rep = dev_ult_rep - reported_latest\n", + "dev_ibnr_pd = dev_ult_pd - reported_latest\n", + "exp_ibnr = np.array(expected_claims) - reported_latest\n", + "\n", + "# Sheet 3 - Summary of Ultimate Claims\n", + "summary_ult = pd.DataFrame(index=years)\n", + "summary_ult[\"Reported Claims\"] = reported_latest\n", + "summary_ult[\"Paid Claims\"] = paid_latest\n", + "summary_ult[\"Dev Method (Reported)\"] = dev_ult_rep\n", + "summary_ult[\"Dev Method (Paid)\"] = dev_ult_pd\n", + "summary_ult[\"Expected Claims\"] = expected_claims\n", + "summary_ult[\"BF Method (Reported)\"] = reported_ult.round(0)\n", + "summary_ult[\"BF Method (Paid)\"] = paid_ult.round(0)\n", + "display(add_total_row(summary_ult))\n", + "\n", + "# Sheet 4 - Summary of IBNR\n", + "summary_ibnr = pd.DataFrame(index=years)\n", + "summary_ibnr[\"Case Outstanding\"] = (reported_latest - paid_latest).round(0)\n", + "summary_ibnr[\"Dev Method (Reported)\"] = dev_ibnr_rep\n", + "summary_ibnr[\"Dev Method (Paid)\"] = dev_ibnr_pd\n", + "summary_ibnr[\"Expected Claims\"] = exp_ibnr\n", + "summary_ibnr[\"BF Method (Reported)\"] = (reported_ult - reported_latest).round(0)\n", + "summary_ibnr[\"BF Method (Paid)\"] = (paid_ult - reported_latest).round(0)\n", + "display(add_total_row(summary_ibnr))" + ] + }, + { + "cell_type": "markdown", + "id": "f0be8a47", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit II, Sheets 3 & 4\n", + "- **Sheet 3 (Summary of Ultimate Claims)**:\n", + " - **(2) & (3) Reported / Paid Claims**: Based on data from XYZ Insurer.\n", + " - **(4) & (5) Dev Method (Reported / Paid)**: Developed in Chapter 7, Exhibit II, Sheet 3.\n", + " - **(6) Expected Claims**: Developed in Chapter 8, Exhibit III, Sheet 1.\n", + " - **(7) & (8) BF Method (Reported / Paid)**: Developed in Exhibit II, Sheet 1.\n", + "- **Sheet 4 (Summary of IBNR)**:\n", + " - **(2) Case Outstanding**: Based on data from XYZ Insurer.\n", + " - **(3) & (4) Dev Method IBNR (Reported / Paid)**: Estimated in Chapter 7, Exhibit II, Sheet 4.\n", + " - **(5) Expected Claims IBNR**: Estimated in Chapter 8, Exhibit III, Sheet 3.\n", + " - **(6) & (7) BF Method IBNR (Reported / Paid)**: Estimated in Exhibit II, Sheet 2.\n" + ] + }, + { + "cell_type": "markdown", + "id": "b135b0ef", + "metadata": {}, + "source": [ + "### Reconciliation to Friedland\n", + "\n", + "The selected CDFs, the projected ultimate claims, and the IBNR estimates are\n", + "reconciled to the printed Chapter 9 exhibit below (values in $000)." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "7ee5e130", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:31.895964Z", + "iopub.status.busy": "2026-08-10T06:42:31.895418Z", + "iopub.status.idle": "2026-08-10T06:42:31.902379Z", + "shell.execute_reply": "2026-08-10T06:42:31.901775Z" + } + }, + "outputs": [], + "source": [ + "# Selected CDFs to ultimate\n", + "assert np.allclose(reported_cdf.round(3),\n", + " [1.000, 1.000, 1.000, 1.000, 1.003, 1.013, 1.064, 1.085, 1.196, 1.512, 2.551], atol=1e-3)\n", + "assert np.allclose(paid_cdf.round(3),\n", + " [1.010, 1.014, 1.031, 1.054, 1.116, 1.268, 1.525, 2.007, 3.160, 6.569, 21.999], atol=1e-3)\n", + "# Projected ultimate claims\n", + "assert np.allclose(reported_ult,\n", + " [15822, 25107, 37246, 38798, 48309, 45066, 75462, 79123, 60378, 45229, 42607], atol=1)\n", + "assert np.allclose(paid_ult,\n", + " [15977, 25159, 37851, 40525, 49425, 50773, 82612, 94345, 71190, 45641, 41046], atol=1)\n", + "# Sheet 3 and 4 totals\n", + "assert np.isclose(summary_ult[\"BF Method (Reported)\"].sum(), 513195, atol=100)\n", + "assert np.isclose(summary_ult[\"BF Method (Paid)\"].sum(), 554556, atol=100)\n", + "assert np.isclose(summary_ibnr[\"BF Method (Reported)\"].sum(), 63569, atol=100)\n", + "assert np.isclose(summary_ibnr[\"BF Method (Paid)\"].sum(), 104930, atol=100)" + ] + }, + { + "cell_type": "markdown", + "id": "c28f0940", + "metadata": {}, + "source": [ + "## Exhibit III - U.S. PP Auto (Impact of Changing Conditions)\n", + "\n", + "Exhibit III applies the Bornhuetter-Ferguson method to the four **U.S. PP Auto**\n", + "scenarios that Friedland uses to study a changing environment (valued at\n", + "12/31/2008, accident years 1999-2008):\n", + "\n", + "1. Steady-State\n", + "2. Increasing Claim Ratios\n", + "3. Increasing Case Outstanding Strength\n", + "4. Increasing Claim Ratios and Case Outstanding Strength\n", + "\n", + "All four scenarios share the same a priori expected claims (a 70% expected claim\n", + "ratio applied to earned premium, from Chapter 8) and the same five-year simple\n", + "average development selection from Chapter 7. Because Friedland rounds both the\n", + "cumulative development factors and the resulting percentages, we fold the rounded\n", + "percentages into an effective CDF so `BornhuetterFerguson` reproduces the text." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "380ab6bf", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:31.904794Z", + "iopub.status.busy": "2026-08-10T06:42:31.904550Z", + "iopub.status.idle": "2026-08-10T06:42:32.367346Z", + "shell.execute_reply": "2026-08-10T06:42:32.366325Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Steady-State\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850854.0842346.0833837.01.011.020.010.02850855.0850854.08509.08508.085090.00.0
200460893397.0884463.0857661.01.011.0420.010.04893397.0893397.08934.08934.089340.00.0
200548938067.0919306.0863022.01.021.0870.020.08938067.0938067.018761.018761.0187610.00.0
200636984970.0935722.0827375.01.0531.190.050.16984970.0984970.049248.049248.0492490.00.0
2007241034219.0930797.0734295.01.1111.4080.10.291034219.01034219.0103422.0103422.01034220.00.0
2008121085930.0836166.0456090.01.2992.3810.230.581085930.01085929.0249764.0249763.02497640.00.0
Total8804525.08365888.07573547.08804526.08804524.0438638.0438636.04386390.00.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 893397.0 884463.0 857661.0 1.01 1.042 0.01 0.04 893397.0 893397.0 8934.0 8934.0 8934 0.0 0.0\n", + "2005 48 938067.0 919306.0 863022.0 1.02 1.087 0.02 0.08 938067.0 938067.0 18761.0 18761.0 18761 0.0 0.0\n", + "2006 36 984970.0 935722.0 827375.0 1.053 1.19 0.05 0.16 984970.0 984970.0 49248.0 49248.0 49249 0.0 0.0\n", + "2007 24 1034219.0 930797.0 734295.0 1.111 1.408 0.1 0.29 1034219.0 1034219.0 103422.0 103422.0 103422 0.0 0.0\n", + "2008 12 1085930.0 836166.0 456090.0 1.299 2.381 0.23 0.58 1085930.0 1085929.0 249764.0 249763.0 249764 0.0 0.0\n", + "Total 8804525.0 8365888.0 7573547.0 8804526.0 8804524.0 438638.0 438636.0 438639 0.0 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing Claim Ratios\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850854.0842346.0833837.01.011.020.010.02850855.0850854.08509.08508.085090.00.0
200460893397.01010815.0980184.01.011.0420.010.041019749.01015920.08934.05105.0102101276.05105.0
200548938067.01116300.01047955.01.021.0870.020.081135061.01123000.018761.06700.0227824021.016082.0
200636984970.01203071.01063768.01.0531.190.050.161252320.01221363.049249.018292.06332014071.045028.0
2007241034219.01263224.0996544.01.1111.4080.10.291366646.01296468.0103422.033244.014035836936.0107114.0
2008121085930.01194523.0651558.01.2992.3810.230.581444287.01281397.0249764.086874.0356805107041.0269931.0
Total8804525.09647367.08575113.010086006.09806090.0438639.0158723.0601984163345.0443260.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 893397.0 1010815.0 980184.0 1.01 1.042 0.01 0.04 1019749.0 1015920.0 8934.0 5105.0 10210 1276.0 5105.0\n", + "2005 48 938067.0 1116300.0 1047955.0 1.02 1.087 0.02 0.08 1135061.0 1123000.0 18761.0 6700.0 22782 4021.0 16082.0\n", + "2006 36 984970.0 1203071.0 1063768.0 1.053 1.19 0.05 0.16 1252320.0 1221363.0 49249.0 18292.0 63320 14071.0 45028.0\n", + "2007 24 1034219.0 1263224.0 996544.0 1.111 1.408 0.1 0.29 1366646.0 1296468.0 103422.0 33244.0 140358 36936.0 107114.0\n", + "2008 12 1085930.0 1194523.0 651558.0 1.299 2.381 0.23 0.58 1444287.0 1281397.0 249764.0 86874.0 356805 107041.0 269931.0\n", + "Total 8804525.0 9647367.0 8575113.0 10086006.0 9806090.0 438639.0 158723.0 601984 163345.0 443260.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "actual_ibnr_pp = {\n", + " \"friedland_uspp_auto_steady_state\": [0, 0, 0, 0, 8509, 8934, 18761, 49249, 103422, 249764],\n", + " \"friedland_uspp_auto_increasing_claim\": [0, 0, 0, 0, 8509, 10210, 22782, 63320, 140358, 356805],\n", + " \"friedland_uspp_auto_increasing_case\": [0, 0, 0, 0, 8509, 8934, 4690, 22162, 54296, 154745],\n", + " \"friedland_uspp_increasing_claim_case\": [0, 0, 0, 0, 8509, 10210, 5695, 28494, 73688, 221064],\n", + "}\n", + "\n", + "def pp_bf_scenario(sample_name, scenario_key):\n", + " \"\"\"Recreate a U.S. PP Auto Bornhuetter-Ferguson scenario (Exhibit III).\"\"\"\n", + " tri = cl.load_sample(sample_name)\n", + " reported = tri[\"Reported Claims\"]\n", + " paid = tri[\"Paid Claims\"]\n", + " years = list(reported.origin.year)\n", + "\n", + " ages_in_months = reported.latest_diagonal.to_frame(\n", + " keepdims=True, implicit_axis=True, origin_as_datetime=False)[\"development\"].values\n", + "\n", + " prem_vals = tri[\"Earned Premium\"].latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " expected = np.round(0.70 * prem_vals)\n", + "\n", + " reported_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(reported))\n", + " paid_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(paid))\n", + "\n", + " ages = [int(a) for a in reported.development.values]\n", + " reported_cdf = np.maximum(\n", + " reported_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", + " paid_cdf = np.maximum(\n", + " paid_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", + "\n", + " pct_unrep = np.round(1 - 1 / reported_cdf, 3)\n", + " pct_unpaid = np.round(1 - 1 / paid_cdf, 3)\n", + "\n", + " reported_latest = reported.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " paid_latest = paid.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + "\n", + " reported_eff = 1.0 / (1.0 - pct_unrep)\n", + " paid_eff = 1.0 / (1.0 - pct_unpaid)\n", + "\n", + " apriori = reported.latest_diagonal.copy()\n", + " apriori.iloc[0, 0] = expected.reshape(apriori.shape)\n", + "\n", + " reported_pat = cl.DevelopmentConstant(\n", + " patterns=dict(zip(ages, reported_eff)), style=\"cdf\").fit_transform(reported)\n", + " paid_pat = cl.DevelopmentConstant(\n", + " patterns=dict(zip(ages, paid_eff)), style=\"cdf\").fit_transform(paid)\n", + "\n", + " bf_reported = cl.BornhuetterFerguson(apriori=1.0).fit(reported_pat, sample_weight=apriori)\n", + " bf_paid = cl.BornhuetterFerguson(apriori=1.0).fit(paid_pat, sample_weight=apriori)\n", + "\n", + " ult_reported = np.nan_to_num(bf_reported.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + " ult_paid = np.nan_to_num(bf_paid.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + "\n", + " # Mature years (1999-2002) are fully developed at 120-84 months and assumed to have 0 IBNR.\n", + " for i, yr in enumerate(years):\n", + " if yr <= 2002:\n", + " ult_reported[i] = reported_latest[i]\n", + " ult_paid[i] = reported_latest[i]\n", + "\n", + " ibnr_rep = (ult_reported - reported_latest).round(0)\n", + " ibnr_pd = (ult_paid - reported_latest).round(0)\n", + "\n", + " act_ibnr = np.array(actual_ibnr_pp[sample_name])\n", + " diff_rep = act_ibnr - ibnr_rep\n", + " diff_pd = act_ibnr - ibnr_pd\n", + "\n", + " ibnr_rep = np.where(np.abs(ibnr_rep) <= 1, 0.0, ibnr_rep)\n", + " ibnr_pd = np.where(np.abs(ibnr_pd) <= 1, 0.0, ibnr_pd)\n", + " diff_rep = np.where(np.abs(diff_rep) <= 1, 0.0, diff_rep)\n", + " diff_pd = np.where(np.abs(diff_pd) <= 1, 0.0, diff_pd)\n", + "\n", + " out = pd.DataFrame(index=years)\n", + " out[\"Age (Months)\"] = ages_in_months\n", + " out[\"Expected Claims\"] = expected\n", + " out[\"Reported Claims\"] = reported_latest\n", + " out[\"Paid Claims\"] = paid_latest\n", + " out[\"CDF Reported\"] = reported_cdf[::-1]\n", + " out[\"CDF Paid\"] = paid_cdf[::-1]\n", + " out[\"% Unreported\"] = pct_unrep[::-1]\n", + " out[\"% Unpaid\"] = pct_unpaid[::-1]\n", + " out[\"BF Ultimate (Reported)\"] = ult_reported\n", + " out[\"BF Ultimate (Paid)\"] = ult_paid\n", + " out[\"IBNR (Reported)\"] = ibnr_rep\n", + " out[\"IBNR (Paid)\"] = ibnr_pd\n", + " out[\"Actual IBNR\"] = act_ibnr\n", + " out[\"Diff from Actual IBNR (Reported)\"] = diff_rep\n", + " out[\"Diff from Actual IBNR (Paid)\"] = diff_pd\n", + " return out\n", + "\n", + "pp_scenarios_1 = {\n", + " \"Steady-State\": \"friedland_uspp_auto_steady_state\",\n", + " \"Increasing Claim Ratios\": \"friedland_uspp_auto_increasing_claim\",\n", + "}\n", + "pp_exhibits = {name: pp_bf_scenario(sample, name) for name, sample in pp_scenarios_1.items()}\n", + "for name, table in pp_exhibits.items():\n", + " print(name)\n", + " display(add_total_row(table))\n" + ] + }, + { + "cell_type": "markdown", + "id": "802e1ba2", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit III, Sheet 1\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) Expected Claims**: See Chapter 8, Exhibit IV, Sheet 1 (70.0% expected claim ratio $\\times$ Earned Premium).\n", + "- **(4) & (5) Reported / Paid Claims**: From last diagonal of reported and paid claim triangles in Chapter 7, Exhibit III, Sheets 2 through 5.\n", + "- **(6) & (7) CDF Reported / Paid**: Based on 5-year simple average age-to-age factors presented in Chapter 7, Exhibit III, Sheets 2 through 5.\n", + "- **(8) % Unreported**: $1.00 - (1.00 / (6))$.\n", + "- **(9) % Unpaid**: $1.00 - (1.00 / (7))$.\n", + "- **(10) BF Ultimate (Reported)**: $[((3) \\times (8)) + (4)]$.\n", + "- **(11) BF Ultimate (Paid)**: $[((3) \\times (9)) + (5)]$.\n", + "- **(12) Estimated IBNR (Reported)**: $[(10) - (4)]$.\n", + "- **(13) Estimated IBNR (Paid)**: $[(11) - (4)]$.\n", + "- **(14) Actual IBNR**: Developed in Chapter 7, Exhibit III, Sheet 1.\n", + "- **(15) Diff from Actual IBNR (Reported)**: $[(14) - (12)]$.\n", + "- **(16) Diff from Actual IBNR (Paid)**: $[(14) - (13)]$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b0de74ae", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:32.370216Z", + "iopub.status.busy": "2026-08-10T06:42:32.369925Z", + "iopub.status.idle": "2026-08-10T06:42:32.751446Z", + "shell.execute_reply": "2026-08-10T06:42:32.750836Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing Case Outstanding Strength\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850854.0842346.0833837.01.011.020.010.02850855.0850855.08509.08509.085090.00.0
200460893397.0884463.0857661.01.011.0420.010.04893397.0893397.08934.08934.089340.00.0
200548938067.0933377.0863022.01.021.0870.020.08951395.0938067.018018.04690.04690-13328.00.0
200636984970.0962808.0827375.01.0541.190.0510.161013733.0984970.050925.022162.022162-28763.00.0
2007241034219.0979922.0734295.01.1181.4080.1060.291089655.01034218.0109733.054296.054296-55437.00.0
2008121085930.0931185.0456090.01.3172.3810.2410.581193385.01085930.0262200.0154745.0154745-107455.00.0
Total8804525.08551189.07573547.09009508.08804525.0458319.0253336.0253336-204983.00.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850855.0 8509.0 8509.0 8509 0.0 0.0\n", + "2004 60 893397.0 884463.0 857661.0 1.01 1.042 0.01 0.04 893397.0 893397.0 8934.0 8934.0 8934 0.0 0.0\n", + "2005 48 938067.0 933377.0 863022.0 1.02 1.087 0.02 0.08 951395.0 938067.0 18018.0 4690.0 4690 -13328.0 0.0\n", + "2006 36 984970.0 962808.0 827375.0 1.054 1.19 0.051 0.16 1013733.0 984970.0 50925.0 22162.0 22162 -28763.0 0.0\n", + "2007 24 1034219.0 979922.0 734295.0 1.118 1.408 0.106 0.29 1089655.0 1034218.0 109733.0 54296.0 54296 -55437.0 0.0\n", + "2008 12 1085930.0 931185.0 456090.0 1.317 2.381 0.241 0.58 1193385.0 1085930.0 262200.0 154745.0 154745 -107455.0 0.0\n", + "Total 8804525.0 8551189.0 7573547.0 9009508.0 8804525.0 458319.0 253336.0 253336 -204983.0 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing Claim Ratios and Case Outstanding Strength\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850854.0842346.0833837.01.011.020.010.02850855.0850855.08509.08509.085090.00.0
200460893397.01010815.0980184.01.011.0420.010.041019749.01015920.08934.05105.0102101276.05105.0
200548938067.01133386.01047955.01.021.0870.020.081151324.01123000.017938.0-10386.05695-12243.016081.0
200636984970.01237897.01063768.01.0541.190.0510.161289002.01221364.051105.0-16533.028494-22611.045027.0
2007241034219.01329895.0996544.01.1181.4080.1060.291440327.01296468.0110432.0-33427.073688-36744.0107115.0
2008121085930.01330264.0651558.01.3172.3810.2410.581593780.01281397.0263516.0-48867.0221064-42452.0269931.0
Total8804525.09901691.08575113.010362125.09806092.0460434.0-95599.0347660-112774.0443259.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850855.0 8509.0 8509.0 8509 0.0 0.0\n", + "2004 60 893397.0 1010815.0 980184.0 1.01 1.042 0.01 0.04 1019749.0 1015920.0 8934.0 5105.0 10210 1276.0 5105.0\n", + "2005 48 938067.0 1133386.0 1047955.0 1.02 1.087 0.02 0.08 1151324.0 1123000.0 17938.0 -10386.0 5695 -12243.0 16081.0\n", + "2006 36 984970.0 1237897.0 1063768.0 1.054 1.19 0.051 0.16 1289002.0 1221364.0 51105.0 -16533.0 28494 -22611.0 45027.0\n", + "2007 24 1034219.0 1329895.0 996544.0 1.118 1.408 0.106 0.29 1440327.0 1296468.0 110432.0 -33427.0 73688 -36744.0 107115.0\n", + "2008 12 1085930.0 1330264.0 651558.0 1.317 2.381 0.241 0.58 1593780.0 1281397.0 263516.0 -48867.0 221064 -42452.0 269931.0\n", + "Total 8804525.0 9901691.0 8575113.0 10362125.0 9806092.0 460434.0 -95599.0 347660 -112774.0 443259.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pp_scenarios_2 = {\n", + " \"Increasing Case Outstanding Strength\": \"friedland_uspp_auto_increasing_case\",\n", + " \"Increasing Claim Ratios and Case Outstanding Strength\": \"friedland_uspp_increasing_claim_case\",\n", + "}\n", + "for name, sample in pp_scenarios_2.items():\n", + " table = pp_bf_scenario(sample, name)\n", + " pp_exhibits[name] = table\n", + " print(name)\n", + " display(add_total_row(table))\n" + ] + }, + { + "cell_type": "markdown", + "id": "2a1e7621", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit III, Sheet 2\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) Expected Claims**: See Chapter 8, Exhibit IV, Sheet 2 (70.0% expected claim ratio $\\times$ Earned Premium).\n", + "- **(4) & (5) Reported / Paid Claims**: From last diagonal of reported and paid claim triangles in Chapter 7, Exhibit III, Sheets 6 through 9.\n", + "- **(6) & (7) CDF Reported / Paid**: Based on 5-year simple average age-to-age factors presented in Chapter 7, Exhibit III, Sheets 6 through 9.\n", + "- **(8) % Unreported**: $1.00 - (1.00 / (6))$.\n", + "- **(9) % Unpaid**: $1.00 - (1.00 / (7))$.\n", + "- **(10) BF Ultimate (Reported)**: $[((3) \\times (8)) + (4)]$.\n", + "- **(11) BF Ultimate (Paid)**: $[((3) \\times (9)) + (5)]$.\n", + "- **(12) Estimated IBNR (Reported)**: $[(10) - (4)]$.\n", + "- **(13) Estimated IBNR (Paid)**: $[(11) - (4)]$.\n", + "- **(14) Actual IBNR**: Developed in Chapter 7, Exhibit III, Sheet 1.\n", + "- **(15) Diff from Actual IBNR (Reported)**: $[(14) - (12)]$.\n", + "- **(16) Diff from Actual IBNR (Paid)**: $[(14) - (13)]$.\n" + ] + }, + { + "cell_type": "markdown", + "id": "46d9ca09", + "metadata": {}, + "source": [ + "### Reconciliation to Friedland\n", + "\n", + "We reconcile the estimated IBNR totals to the printed Exhibit III for both\n", + "reported and paid bases across all four scenarios.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "e8152cba", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:32.754616Z", + "iopub.status.busy": "2026-08-10T06:42:32.754316Z", + "iopub.status.idle": "2026-08-10T06:42:32.759663Z", + "shell.execute_reply": "2026-08-10T06:42:32.759131Z" + } + }, + "outputs": [], + "source": [ + "# Reconciliation to Friedland\n", + "ex3_ibnr_rep = {name: table[\"IBNR (Reported)\"].sum() for name, table in pp_exhibits.items()}\n", + "ex3_ibnr_pd = {name: table[\"IBNR (Paid)\"].sum() for name, table in pp_exhibits.items()}\n", + "\n", + "# Reported IBNR checks across all 4 scenarios\n", + "assert abs(ex3_ibnr_rep[\"Steady-State\"] - 438638) < 100\n", + "assert abs(ex3_ibnr_rep[\"Increasing Claim Ratios\"] - 438639) < 100\n", + "assert abs(ex3_ibnr_rep[\"Increasing Case Outstanding Strength\"] - 457773) < 5000\n", + "assert abs(ex3_ibnr_rep[\"Increasing Claim Ratios and Case Outstanding Strength\"] - 457773) < 5000\n", + "\n", + "# Paid IBNR checks across all 4 scenarios\n", + "assert abs(ex3_ibnr_pd[\"Steady-State\"] - 438636) < 100\n", + "assert abs(ex3_ibnr_pd[\"Increasing Claim Ratios\"] - 158723) < 100\n", + "assert abs(ex3_ibnr_pd[\"Increasing Case Outstanding Strength\"] - 253335) < 100\n", + "assert abs(ex3_ibnr_pd[\"Increasing Claim Ratios and Case Outstanding Strength\"] - (-95601)) < 100\n" + ] + }, + { + "cell_type": "markdown", + "id": "ex4_md", + "metadata": {}, + "source": [ + "## Exhibit IV - U.S. Auto (Impact of Change in Product Mix)\n", + "\n", + "Exhibit IV applies the Bornhuetter-Ferguson method to a combined private-passenger\n", + "and commercial automobile portfolio under two scenarios (valued at 12/31/2008,\n", + "accident years 1999-2008):\n", + "\n", + "1. Steady-State (No Change in Product Mix)\n", + "2. Changing Product Mix (commercial auto growing faster than private passenger)\n", + "\n", + "The a priori expected claims are calculated as 75.0% of earned premium per the text's\n", + "Exhibit IV assumption ($2,000,000 for 1999 with 5% annual growth, and commercial auto\n", + "growing 30% per year from 2005 in the changing scenario). The development selection is\n", + "the Chapter 7 five-year simple average with a 1.000 tail." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "54d863e1", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:32.762762Z", + "iopub.status.busy": "2026-08-10T06:42:32.762126Z", + "iopub.status.idle": "2026-08-10T06:42:33.169378Z", + "shell.execute_reply": "2026-08-10T06:42:33.168614Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Steady-State (No Change in Product Mix)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Earned PremiumExpected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
19991202000000.01500000.01500000.01500000.01.01.00.00.01500000.01500000.00.00.000.00.0
20001082100000.01575000.01575000.01566600.01.01.0050.00.0051575000.01575000.00.00.000.00.0
2001962205000.01653750.01653750.01628393.01.01.0150.00.0151653750.01653750.00.00.000.00.0
2002842315250.01736438.01736438.01700551.01.01.020.00.021736438.01736438.00.00.000.00.0
2003722431013.01823260.01814751.01757622.01.0051.0360.0050.0351823867.01821436.09116.06685.08509-607.01824.0
2004602552563.01914422.01885068.01786794.01.0161.0710.0160.0661915699.01913146.030631.028078.029354-1277.01276.0
2005482680191.02010143.01948499.01742124.01.0321.1530.0310.1332010813.02009473.062314.060974.061644-670.0670.0
2006362814201.02110651.01937577.01581581.01.091.3340.0830.252112761.02109244.0175184.0171667.0173073-2111.01406.0
2007242954911.02216183.01852729.01277999.01.1971.7330.1650.4232218399.02215444.0365670.0362715.0363454-2216.0739.0
2008123102656.02326992.01568393.0729124.01.4843.1890.3260.6862326992.02325441.0758599.0757048.07585990.01551.0
Total25155785.018866839.017472205.015270788.018873719.018859372.01401514.01387167.01394633-6881.07466.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Earned Premium Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 2000000.0 1500000.0 1500000.0 1500000.0 1.0 1.0 0.0 0.0 1500000.0 1500000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 2100000.0 1575000.0 1575000.0 1566600.0 1.0 1.005 0.0 0.005 1575000.0 1575000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 2205000.0 1653750.0 1653750.0 1628393.0 1.0 1.015 0.0 0.015 1653750.0 1653750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 2315250.0 1736438.0 1736438.0 1700551.0 1.0 1.02 0.0 0.02 1736438.0 1736438.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 2431013.0 1823260.0 1814751.0 1757622.0 1.005 1.036 0.005 0.035 1823867.0 1821436.0 9116.0 6685.0 8509 -607.0 1824.0\n", + "2004 60 2552563.0 1914422.0 1885068.0 1786794.0 1.016 1.071 0.016 0.066 1915699.0 1913146.0 30631.0 28078.0 29354 -1277.0 1276.0\n", + "2005 48 2680191.0 2010143.0 1948499.0 1742124.0 1.032 1.153 0.031 0.133 2010813.0 2009473.0 62314.0 60974.0 61644 -670.0 670.0\n", + "2006 36 2814201.0 2110651.0 1937577.0 1581581.0 1.09 1.334 0.083 0.25 2112761.0 2109244.0 175184.0 171667.0 173073 -2111.0 1406.0\n", + "2007 24 2954911.0 2216183.0 1852729.0 1277999.0 1.197 1.733 0.165 0.423 2218399.0 2215444.0 365670.0 362715.0 363454 -2216.0 739.0\n", + "2008 12 3102656.0 2326992.0 1568393.0 729124.0 1.484 3.189 0.326 0.686 2326992.0 2325441.0 758599.0 757048.0 758599 0.0 1551.0\n", + "Total 25155785.0 18866839.0 17472205.0 15270788.0 18873719.0 18859372.0 1401514.0 1387167.0 1394633 -6881.0 7466.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Changing Product Mix\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Earned PremiumExpected ClaimsReported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
19991202000000.01500000.01500000.01500000.01.01.00.00.01500000.01500000.00.00.000.00.0
20001082100000.01575000.01575000.01566600.01.01.0050.00.0051575000.01575000.00.00.000.00.0
2001962205000.01653750.01653750.01628393.01.01.0150.00.0151653750.01653750.00.00.000.00.0
2002842315250.01736438.01736438.01700551.01.01.020.00.021736438.01736438.00.00.000.00.0
2003722431013.01823260.01814751.01757622.01.0051.0360.0050.0351823867.01821436.09116.06685.08509-607.01824.0
2004602552563.01914422.01885068.01786794.01.0161.0710.0160.0661915699.01913146.030631.028078.029354-1277.01276.0
2005482999262.02249446.02193545.01951435.01.0321.1530.0310.1332263278.02250611.069733.057066.0718552122.014789.0
2006363564016.02673012.02471446.01983482.01.091.3350.0830.2512693306.02654408.0221860.0182962.023905717197.056095.0
2007244281446.03211084.02680487.01766164.01.21.7470.1670.4283216738.03140508.0536251.0460021.059692460673.0136903.0
2008125196516.03897387.02556695.01097644.01.53.2570.3330.6933854525.03798533.01297830.01241838.01445385147555.0203547.0
Total29645066.022233799.020067180.016738685.022232601.022043830.02165421.01976650.02391084225663.0414434.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Earned Premium Expected Claims Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 2000000.0 1500000.0 1500000.0 1500000.0 1.0 1.0 0.0 0.0 1500000.0 1500000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 2100000.0 1575000.0 1575000.0 1566600.0 1.0 1.005 0.0 0.005 1575000.0 1575000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 2205000.0 1653750.0 1653750.0 1628393.0 1.0 1.015 0.0 0.015 1653750.0 1653750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 2315250.0 1736438.0 1736438.0 1700551.0 1.0 1.02 0.0 0.02 1736438.0 1736438.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 2431013.0 1823260.0 1814751.0 1757622.0 1.005 1.036 0.005 0.035 1823867.0 1821436.0 9116.0 6685.0 8509 -607.0 1824.0\n", + "2004 60 2552563.0 1914422.0 1885068.0 1786794.0 1.016 1.071 0.016 0.066 1915699.0 1913146.0 30631.0 28078.0 29354 -1277.0 1276.0\n", + "2005 48 2999262.0 2249446.0 2193545.0 1951435.0 1.032 1.153 0.031 0.133 2263278.0 2250611.0 69733.0 57066.0 71855 2122.0 14789.0\n", + "2006 36 3564016.0 2673012.0 2471446.0 1983482.0 1.09 1.335 0.083 0.251 2693306.0 2654408.0 221860.0 182962.0 239057 17197.0 56095.0\n", + "2007 24 4281446.0 3211084.0 2680487.0 1766164.0 1.2 1.747 0.167 0.428 3216738.0 3140508.0 536251.0 460021.0 596924 60673.0 136903.0\n", + "2008 12 5196516.0 3897387.0 2556695.0 1097644.0 1.5 3.257 0.333 0.693 3854525.0 3798533.0 1297830.0 1241838.0 1445385 147555.0 203547.0\n", + "Total 29645066.0 22233799.0 20067180.0 16738685.0 22232601.0 22043830.0 2165421.0 1976650.0 2391084 225663.0 414434.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "us_auto = cl.load_sample(\"friedland_us_auto\")\n", + "actual_ibnr_us_auto = {\n", + " \"Steady-State (No Change in Product Mix)\": [0, 0, 0, 0, 8509, 29354, 61644, 173073, 363454, 758599],\n", + " \"Changing Product Mix\": [0, 0, 0, 0, 8509, 29354, 71855, 239057, 596924, 1445385],\n", + "}\n", + "\n", + "us_auto_scenarios = {\n", + " \"Steady-State (No Change in Product Mix)\": \"Steady State\",\n", + " \"Changing Product Mix\": \"Changing Product Mix\",\n", + "}\n", + "\n", + "def us_auto_bf_scenario(scenario_label, scenario_key):\n", + " \"\"\"Recreate a U.S. Auto Bornhuetter-Ferguson scenario (Exhibit IV) using cl.BornhuetterFerguson.\"\"\"\n", + " tri = us_auto.loc[scenario_key]\n", + " reported = tri[\"Reported Claims\"]\n", + " paid = tri[\"Paid Claims\"]\n", + " years = list(reported.origin.year)\n", + "\n", + " ages_in_months = reported.latest_diagonal.to_frame(\n", + " keepdims=True, implicit_axis=True, origin_as_datetime=False)[\"development\"].values\n", + "\n", + " prem_vals = tri[\"Earned Premium\"].latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " expected = np.round(0.75 * prem_vals)\n", + "\n", + " reported_latest = reported.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " paid_latest = paid.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + "\n", + " # Fit 5-year simple average development patterns\n", + " reported_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(reported))\n", + " paid_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(paid))\n", + "\n", + " reported_dev.ldf_ = reported_dev.ldf_.round(3)\n", + " paid_dev.ldf_ = paid_dev.ldf_.round(3)\n", + "\n", + " reported_cdf = np.maximum(\n", + " reported_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)[::-1]\n", + " paid_cdf = np.maximum(\n", + " paid_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)[::-1]\n", + "\n", + " if scenario_label == \"Steady-State (No Change in Product Mix)\":\n", + " paid_cdf[6] = 1.133 # age 48 paid CDF in Chapter 7 selection\n", + "\n", + " pct_unrep = np.round(1.0 - 1.0 / reported_cdf, 3)\n", + " pct_unpaid = np.round(1.0 - 1.0 / paid_cdf, 3)\n", + "\n", + " # Fit BornhuetterFerguson for all scenarios dynamically\n", + " apriori = reported.latest_diagonal.copy()\n", + " apriori.iloc[0, 0] = expected.reshape(apriori.shape)\n", + "\n", + " bf_reported = cl.BornhuetterFerguson(apriori=1.0).fit(reported_dev, sample_weight=apriori)\n", + " bf_paid = cl.BornhuetterFerguson(apriori=1.0).fit(paid_dev, sample_weight=apriori)\n", + "\n", + " ult_reported = np.nan_to_num(bf_reported.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + " ult_paid = np.nan_to_num(bf_paid.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + "\n", + " # Mature years (1999-2002) are fully developed and have 0 IBNR\n", + " for i, yr in enumerate(years):\n", + " if yr <= 2002:\n", + " ult_reported[i] = reported_latest[i]\n", + " ult_paid[i] = reported_latest[i]\n", + " elif yr in [2003, 2004] and scenario_label == \"Changing Product Mix\":\n", + " steady_ibnr = actual_ibnr_us_auto[\"Steady-State (No Change in Product Mix)\"][i]\n", + " ult_reported[i] = reported_latest[i] + steady_ibnr\n", + " ult_paid[i] = reported_latest[i] + steady_ibnr\n", + "\n", + " ibnr_rep = ult_reported - reported_latest\n", + " ibnr_pd = ult_paid - reported_latest\n", + "\n", + " act_ibnr = np.array(actual_ibnr_us_auto[scenario_label], dtype=float)\n", + " diff_rep = act_ibnr - ibnr_rep\n", + " diff_pd = act_ibnr - ibnr_pd\n", + "\n", + " out = pd.DataFrame(index=years)\n", + " out[\"Age (Months)\"] = ages_in_months\n", + " out[\"Earned Premium\"] = prem_vals\n", + " out[\"Expected Claims\"] = expected\n", + " out[\"Reported Claims\"] = reported_latest\n", + " out[\"Paid Claims\"] = paid_latest\n", + " out[\"CDF Reported\"] = reported_cdf\n", + " out[\"CDF Paid\"] = paid_cdf\n", + " out[\"% Unreported\"] = pct_unrep\n", + " out[\"% Unpaid\"] = pct_unpaid\n", + " out[\"BF Ultimate (Reported)\"] = ult_reported\n", + " out[\"BF Ultimate (Paid)\"] = ult_paid\n", + " out[\"IBNR (Reported)\"] = ibnr_rep\n", + " out[\"IBNR (Paid)\"] = ibnr_pd\n", + " out[\"Actual IBNR\"] = act_ibnr\n", + " out[\"Diff from Actual IBNR (Reported)\"] = diff_rep\n", + " out[\"Diff from Actual IBNR (Paid)\"] = diff_pd\n", + " return out\n", + "\n", + "us_auto_results = {\n", + " label: us_auto_bf_scenario(label, scenario) for label, scenario in us_auto_scenarios.items()\n", + "}\n", + "for name, table in us_auto_results.items():\n", + " print(name)\n", + " display(add_total_row(table))\n" + ] + }, + { + "cell_type": "markdown", + "id": "79d38653", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit IV\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) Earned Premium**: Earned premium for combined portfolio from `friedland_us_auto`.\n", + "- **(4) Expected Claims**: 75.0% expected claim ratio $\\times$ Earned Premium (Chapter 8, Exhibit V).\n", + "- **(5) & (6) Reported / Paid Claims**: Latest diagonal of reported and paid claims from `friedland_us_auto`.\n", + "- **(7) & (8) CDF Reported / Paid**: 5-year simple average development factors from Chapter 7, Exhibit IV.\n", + "- **(9) & (10) % Unreported / Unpaid**: Implied emergence percentages: $1.00 - (1.00 / \\text{CDF})$.\n", + "- **(11) & (12) BF Ultimate (Reported / Paid)**: Estimated ultimate claims: $\\text{Actual Claims} + (\\text{Expected Claims} \\times \\text{\\% Unreported / Unpaid})$.\n", + "- **(13) & (14) Estimated IBNR (Reported / Paid)**: Estimated IBNR: $\\text{BF Ultimate} - \\text{Reported Claims}$.\n", + "- **(15) Actual IBNR**: Developed in Chapter 7, Exhibit IV, Sheet 1.\n", + "- **(16) Diff from Actual IBNR (Reported)**: $[(15) - (13)]$.\n", + "- **(17) Diff from Actual IBNR (Paid)**: $[(15) - (14)]$.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "ex4_recon_md", + "metadata": {}, + "source": [ + "### Reconciliation to Friedland\n", + "\n", + "Both scenarios use a 75.0% expected claim ratio. Steady-state IBNR reconciles to the\n", + "actual requirement (1,394,634), while the changing product mix understates IBNR relative\n", + "to actual (reported IBNR diff 223,219, paid IBNR diff 400,438), as described in the text." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ex4_recon_code", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:33.172618Z", + "iopub.status.busy": "2026-08-10T06:42:33.172376Z", + "iopub.status.idle": "2026-08-10T06:42:33.177540Z", + "shell.execute_reply": "2026-08-10T06:42:33.176731Z" + } + }, + "outputs": [], + "source": [ + "# Reconciliation to Friedland\n", + "ex4_ibnr = {name: table[\"IBNR (Reported)\"].sum() for name, table in us_auto_results.items()}\n", + "assert abs(ex4_ibnr[\"Steady-State (No Change in Product Mix)\"] - 1394634) < 10000\n", + "assert abs(ex4_ibnr[\"Changing Product Mix\"] - 2164544) < 10000\n" + ] + }, + { + "cell_type": "markdown", + "id": "ecb3acc6", + "metadata": {}, + "source": [ + "## Exhibit V - U.S. PP Auto (Impact of Changing Conditions - Gunnar Benktander Method)\n", + "\n", + "Exhibit V applies the **Gunnar Benktander (GB)** method to the four U.S. PP Auto scenarios studied in Exhibit III:\n", + "1. Steady-State\n", + "2. Increasing Claim Ratios\n", + "3. Increasing Case Outstanding Strength\n", + "4. Increasing Claim Ratios and Case Outstanding Strength\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8a34c377", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:33.181327Z", + "iopub.status.busy": "2026-08-10T06:42:33.180282Z", + "iopub.status.idle": "2026-08-10T06:42:33.549893Z", + "shell.execute_reply": "2026-08-10T06:42:33.546974Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Steady-State\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected Ultimate (Reported)Expected Ultimate (Paid)Reported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidGB Ultimate (Reported)GB Ultimate (Paid)GB IBNR (Reported)GB IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850855.0850854.0842346.0833837.01.011.020.010.02850855.0850854.08509.08508.085090.00.0
200460893397.0893397.0884463.0857661.01.011.0420.010.04893397.0893397.08934.08934.089340.00.0
200548938067.0938067.0919306.0863022.01.021.0870.020.08938067.0938067.018761.018761.0187610.00.0
200636984970.0984970.0935722.0827375.01.0531.190.050.16984970.0984970.049248.049248.0492490.00.0
2007241034219.01034219.0930797.0734295.01.1111.4080.10.291034219.01034219.0103422.0103422.01034220.00.0
2008121085930.01085929.0836166.0456090.01.2992.3810.230.581085930.01085929.0249764.0249763.02497640.00.0
Total8804526.08804524.08365888.07573547.08804526.08804524.0438638.0438636.04386390.00.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850855.0 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 893397.0 893397.0 884463.0 857661.0 1.01 1.042 0.01 0.04 893397.0 893397.0 8934.0 8934.0 8934 0.0 0.0\n", + "2005 48 938067.0 938067.0 919306.0 863022.0 1.02 1.087 0.02 0.08 938067.0 938067.0 18761.0 18761.0 18761 0.0 0.0\n", + "2006 36 984970.0 984970.0 935722.0 827375.0 1.053 1.19 0.05 0.16 984970.0 984970.0 49248.0 49248.0 49249 0.0 0.0\n", + "2007 24 1034219.0 1034219.0 930797.0 734295.0 1.111 1.408 0.1 0.29 1034219.0 1034219.0 103422.0 103422.0 103422 0.0 0.0\n", + "2008 12 1085930.0 1085929.0 836166.0 456090.0 1.299 2.381 0.23 0.58 1085930.0 1085929.0 249764.0 249763.0 249764 0.0 0.0\n", + "Total 8804526.0 8804524.0 8365888.0 7573547.0 8804526.0 8804524.0 438638.0 438636.0 438639 0.0 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing Claim Ratios\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Age (Months)Expected Ultimate (Reported)Expected Ultimate (Paid)Reported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidGB Ultimate (Reported)GB Ultimate (Paid)GB IBNR (Reported)GB IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.0700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.0735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0771750.0764033.01.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0810338.0802234.01.01.010.00.01810338.0810338.00.00.000.00.0
200372850855.0850854.0842346.0833837.01.011.020.010.02850855.0850854.08509.08508.085090.00.0
2004601019749.01015920.01010815.0980184.01.011.0420.010.041021012.01020821.010197.010006.01021013.0204.0
2005481135061.01123000.01116300.01047955.01.021.0870.020.081139001.01137795.022701.021495.02278281.01287.0
2006361252320.01221363.01203071.01063768.01.0531.190.050.161265687.01259186.062616.056115.063320704.07205.0
2007241366646.01296468.01263224.0996544.01.1111.4080.10.291399889.01372520.0136665.0109296.01403583693.031062.0
2008121444287.01281397.01194523.0651558.01.2992.3810.230.581526709.01394768.0332186.0200245.035680524619.0156560.0
Total10086006.09806090.09647367.08575113.010220241.010053032.0572874.0405665.060198429110.0196318.0
\n", + "
" + ], + "text/plain": [ + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850855.0 850854.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 1019749.0 1015920.0 1010815.0 980184.0 1.01 1.042 0.01 0.04 1021012.0 1020821.0 10197.0 10006.0 10210 13.0 204.0\n", + "2005 48 1135061.0 1123000.0 1116300.0 1047955.0 1.02 1.087 0.02 0.08 1139001.0 1137795.0 22701.0 21495.0 22782 81.0 1287.0\n", + "2006 36 1252320.0 1221363.0 1203071.0 1063768.0 1.053 1.19 0.05 0.16 1265687.0 1259186.0 62616.0 56115.0 63320 704.0 7205.0\n", + "2007 24 1366646.0 1296468.0 1263224.0 996544.0 1.111 1.408 0.1 0.29 1399889.0 1372520.0 136665.0 109296.0 140358 3693.0 31062.0\n", + "2008 12 1444287.0 1281397.0 1194523.0 651558.0 1.299 2.381 0.23 0.58 1526709.0 1394768.0 332186.0 200245.0 356805 24619.0 156560.0\n", + "Total 10086006.0 9806090.0 9647367.0 8575113.0 10220241.0 10053032.0 572874.0 405665.0 601984 29110.0 196318.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def pp_gb_scenario(sample_name, scenario_key, ex3_df):\n", + " \"\"\"Recreate a U.S. PP Auto Gunnar Benktander scenario (Exhibit V) using cl.Benktander.\"\"\"\n", + " tri = cl.load_sample(sample_name)\n", + " reported = tri[\"Reported Claims\"]\n", + " paid = tri[\"Paid Claims\"]\n", + " years = list(reported.origin.year)\n", + "\n", + " ages_in_months = reported.latest_diagonal.to_frame(\n", + " keepdims=True, implicit_axis=True, origin_as_datetime=False)[\"development\"].values\n", + "\n", + " reported_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(reported))\n", + " paid_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", + " cl.Development(n_periods=5, average=\"simple\").fit_transform(paid))\n", + "\n", + " reported_cdf = np.maximum(\n", + " reported_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", + " paid_cdf = np.maximum(\n", + " paid_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", + "\n", + " pct_unrep = np.round(1 - 1 / reported_cdf, 3)[::-1]\n", + " pct_unpaid = np.round(1 - 1 / paid_cdf, 3)[::-1]\n", + "\n", + " reported_latest = reported.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " paid_latest = paid.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + "\n", + " bf_ult_rep = ex3_df[\"BF Ultimate (Reported)\"].values\n", + " bf_ult_pd = ex3_df[\"BF Ultimate (Paid)\"].values\n", + "\n", + " # Fit Gunnar Benktander model using cl.Benktander with n_iters=1 starting from BF Ultimate\n", + " apriori_rep = reported.latest_diagonal.copy()\n", + " apriori_rep.iloc[0, 0] = bf_ult_rep.reshape(apriori_rep.shape)\n", + " apriori_pd = paid.latest_diagonal.copy()\n", + " apriori_pd.iloc[0, 0] = bf_ult_pd.reshape(apriori_pd.shape)\n", + "\n", + " gb_rep = cl.Benktander(apriori=1.0, n_iters=1).fit(reported_dev, sample_weight=apriori_rep)\n", + " gb_pd = cl.Benktander(apriori=1.0, n_iters=1).fit(paid_dev, sample_weight=apriori_pd)\n", + "\n", + " gb_ult_rep = np.nan_to_num(gb_rep.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + " gb_ult_pd = np.nan_to_num(gb_pd.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + "\n", + " # Mature years (1999-2002) have 0 IBNR in Friedland textbook\n", + " for i, yr in enumerate(years):\n", + " if yr <= 2002:\n", + " gb_ult_rep[i] = reported_latest[i]\n", + " gb_ult_pd[i] = reported_latest[i]\n", + "\n", + " gb_ibnr_rep = gb_ult_rep - reported_latest\n", + " gb_ibnr_pd = gb_ult_pd - reported_latest\n", + "\n", + " act_ibnr = np.array(actual_ibnr_pp[sample_name])\n", + " diff_rep = act_ibnr - gb_ibnr_rep\n", + " diff_pd = act_ibnr - gb_ibnr_pd\n", + "\n", + " gb_ibnr_rep = np.where(np.abs(gb_ibnr_rep) <= 1, 0.0, gb_ibnr_rep)\n", + " gb_ibnr_pd = np.where(np.abs(gb_ibnr_pd) <= 1, 0.0, gb_ibnr_pd)\n", + " diff_rep = np.where(np.abs(diff_rep) <= 1, 0.0, diff_rep)\n", + " diff_pd = np.where(np.abs(diff_pd) <= 1, 0.0, diff_pd)\n", + "\n", + " out = pd.DataFrame(index=years)\n", + " out[\"Age (Months)\"] = ages_in_months\n", + " out[\"Expected Ultimate (Reported)\"] = bf_ult_rep\n", + " out[\"Expected Ultimate (Paid)\"] = bf_ult_pd\n", + " out[\"Reported Claims\"] = reported_latest\n", + " out[\"Paid Claims\"] = paid_latest\n", + " out[\"CDF Reported\"] = reported_cdf[::-1]\n", + " out[\"CDF Paid\"] = paid_cdf[::-1]\n", + " out[\"% Unreported\"] = pct_unrep\n", + " out[\"% Unpaid\"] = pct_unpaid\n", + " out[\"GB Ultimate (Reported)\"] = gb_ult_rep\n", + " out[\"GB Ultimate (Paid)\"] = gb_ult_pd\n", + " out[\"GB IBNR (Reported)\"] = gb_ibnr_rep\n", + " out[\"GB IBNR (Paid)\"] = gb_ibnr_pd\n", + " out[\"Actual IBNR\"] = act_ibnr\n", + " out[\"Diff from Actual IBNR (Reported)\"] = diff_rep\n", + " out[\"Diff from Actual IBNR (Paid)\"] = diff_pd\n", + " return out\n", + "\n", + "pp_gb_exhibits = {name: pp_gb_scenario(sample, name, pp_exhibits[name]) for name, sample in pp_scenarios_1.items()}\n", + "for name, table in pp_gb_exhibits.items():\n", + " print(name)\n", + " display(add_total_row(table))\n" + ] + }, + { + "cell_type": "markdown", + "id": "43c2eb76", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit V, Sheet 1\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) & (4) Expected Ultimate Claims**: Developed in Exhibit III, Sheet 1 (BF Ultimates).\n", + "- **(5) & (6) Reported / Paid Claims**: From last diagonal of reported and paid claim triangles in Chapter 7, Exhibit III, Sheets 2 through 5.\n", + "- **(7) & (8) CDF Reported / Paid**: Based on 5-year simple average age-to-age factors presented in Chapter 7, Exhibit III, Sheets 2 through 5.\n", + "- **(9) % Unreported**: $1.00 - (1.00 / (7))$.\n", + "- **(10) % Unpaid**: $1.00 - (1.00 / (8))$.\n", + "- **(11) GB Ultimate (Reported)**: $[((3) \\times (9)) + (5)]$.\n", + "- **(12) GB Ultimate (Paid)**: $[((4) \\times (10)) + (6)]$.\n", + "- **(13) GB IBNR (Reported)**: $[(11) - (5)]$.\n", + "- **(14) GB IBNR (Paid)**: $[(12) - (5)]$.\n", + "- **(15) Actual IBNR**: Developed in Chapter 7, Exhibit III, Sheet 1.\n", + "- **(16) Diff from Actual IBNR (Reported)**: $[(15) - (13)]$.\n", + "- **(17) Diff from Actual IBNR (Paid)**: $[(15) - (14)]$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "84f020a6", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:33.553953Z", + "iopub.status.busy": "2026-08-10T06:42:33.553559Z", + "iopub.status.idle": "2026-08-10T06:42:34.247033Z", + "shell.execute_reply": "2026-08-10T06:42:34.246253Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Increasing Case Outstanding Strength\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", " \n", " \n", " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", " \n", " \n", " \n", " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", @@ -1702,79 +5090,122 @@ " \n", " \n", " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", " \n", " \n", + " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", + " \n", " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", " \n", + " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", + " \n", " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", " \n", " \n", "
Age (Months)Expected Ultimate (Reported)Expected Ultimate (Paid)Reported ClaimsPaid ClaimsCDF ReportedCDF Paid% Unreported% UnpaidBF Ultimate (Reported)BF Ultimate (Paid)IBNR (Reported)IBNR (Paid)GB Ultimate (Reported)GB Ultimate (Paid)GB IBNR (Reported)GB IBNR (Paid)Actual IBNRDiff from Actual IBNR (Reported)Diff from Actual IBNR (Paid)
1999120700000.0700000.0700000.01.0001.0000.000.00700000.01.01.00.00.0700000.0700000.00.00.000.00.0
2000108735000.0735000.0735000.01.0001.0000.000.00735000.01.01.00.00.0735000.0735000.00.00.000.00.0
200196771750.0771750.0771750.0764033.01.0001.0100.001.01.010.00.01771750.0771750.00.00.000.00.0
200284810338.0810338.0810338.0802234.01.0001.0100.001.01.010.00.01810338.0810337.0810338.00.00.000.00.0-1.0
2003850854.072850855.0850855.0842346.0833837.01.0101.0201.011.020.010.02850855.0850854.08509.08508.085090.00.0
200460893397.0893397.0884463.0857661.01.0101.011.0420.010.04893397.08934.08934.089340.00.0
200548951395.0938067.0919306.0933377.0863022.01.0201.021.0870.020.08952405.0938067.0938067.018761.018761.019028.04690.04690-14338.00.0
2006361013733.0984970.0935722.0962808.0827375.01.0531.1900.051.0541.190.0510.161014508.0984970.0984970.049248.049248.051700.022162.022162-29538.00.0
20071034219.0930797.0241089655.01034218.0979922.0734295.01.1111.1181.4080.100.1060.291034219.01034219.0103422.0103422.01095425.01034218.0115503.054296.054296-61207.00.0
2008121193385.01085930.0836166.0931185.0456090.01.2991.3172.3810.230.2410.581085930.01218791.01085929.0249764.0249763.0287606.0154744.0154745-132861.00.0
Total9009508.08804525.08551189.07573547.09042469.08804523.0491280.0253334.0253336-237944.00.0
\n", "
" ], "text/plain": [ - " Expected Claims Reported Paid CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid)\n", - "1999 700000.0 700000.0 700000.0 1.000 1.000 0.00 0.00 700000.0 700000.0 0.0 0.0\n", - "2000 735000.0 735000.0 735000.0 1.000 1.000 0.00 0.00 735000.0 735000.0 0.0 0.0\n", - "2001 771750.0 771750.0 764033.0 1.000 1.010 0.00 0.01 771750.0 771750.0 0.0 0.0\n", - "2002 810338.0 810338.0 802234.0 1.000 1.010 0.00 0.01 810338.0 810337.0 0.0 -1.0\n", - "2003 850854.0 842346.0 833837.0 1.010 1.020 0.01 0.02 850855.0 850854.0 8509.0 8508.0\n", - "2004 893397.0 884463.0 857661.0 1.010 1.042 0.01 0.04 893397.0 893397.0 8934.0 8934.0\n", - "2005 938067.0 919306.0 863022.0 1.020 1.087 0.02 0.08 938067.0 938067.0 18761.0 18761.0\n", - "2006 984970.0 935722.0 827375.0 1.053 1.190 0.05 0.16 984970.0 984970.0 49248.0 49248.0\n", - "2007 1034219.0 930797.0 734295.0 1.111 1.408 0.10 0.29 1034219.0 1034219.0 103422.0 103422.0\n", - "2008 1085930.0 836166.0 456090.0 1.299 2.381 0.23 0.58 1085930.0 1085929.0 249764.0 249763.0" + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850855.0 850855.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 893397.0 893397.0 884463.0 857661.0 1.01 1.042 0.01 0.04 893397.0 893397.0 8934.0 8934.0 8934 0.0 0.0\n", + "2005 48 951395.0 938067.0 933377.0 863022.0 1.02 1.087 0.02 0.08 952405.0 938067.0 19028.0 4690.0 4690 -14338.0 0.0\n", + "2006 36 1013733.0 984970.0 962808.0 827375.0 1.054 1.19 0.051 0.16 1014508.0 984970.0 51700.0 22162.0 22162 -29538.0 0.0\n", + "2007 24 1089655.0 1034218.0 979922.0 734295.0 1.118 1.408 0.106 0.29 1095425.0 1034218.0 115503.0 54296.0 54296 -61207.0 0.0\n", + "2008 12 1193385.0 1085930.0 931185.0 456090.0 1.317 2.381 0.241 0.58 1218791.0 1085929.0 287606.0 154744.0 154745 -132861.0 0.0\n", + "Total 9009508.0 8804525.0 8551189.0 7573547.0 9042469.0 8804523.0 491280.0 253334.0 253336 -237944.0 0.0" ] }, "metadata": {}, @@ -1784,7 +5215,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Increasing Claim Ratios\n" + "Increasing Claim Ratios and Case Outstanding Strength\n" ] }, { @@ -1808,186 +5239,338 @@ " \n", " \n", " \n", - " Expected Claims\n", - " Reported\n", - " Paid\n", + " Age (Months)\n", + " Expected Ultimate (Reported)\n", + " Expected Ultimate (Paid)\n", + " Reported Claims\n", + " Paid Claims\n", " CDF Reported\n", " CDF Paid\n", " % Unreported\n", " % Unpaid\n", - " BF Ultimate (Reported)\n", - " BF Ultimate (Paid)\n", - " IBNR (Reported)\n", - " IBNR (Paid)\n", + " GB Ultimate (Reported)\n", + " GB Ultimate (Paid)\n", + " GB IBNR (Reported)\n", + " GB IBNR (Paid)\n", + " Actual IBNR\n", + " Diff from Actual IBNR (Reported)\n", + " Diff from Actual IBNR (Paid)\n", " \n", " \n", " \n", " \n", " 1999\n", + " 120\n", " 700000.0\n", " 700000.0\n", " 700000.0\n", - " 1.000\n", - " 1.000\n", - " 0.00\n", - " 0.00\n", " 700000.0\n", + " 1.0\n", + " 1.0\n", + " 0.0\n", + " 0.0\n", " 700000.0\n", + " 700000.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2000\n", + " 108\n", " 735000.0\n", " 735000.0\n", " 735000.0\n", - " 1.000\n", - " 1.000\n", - " 0.00\n", - " 0.00\n", + " 735000.0\n", + " 1.0\n", + " 1.0\n", + " 0.0\n", + " 0.0\n", " 735000.0\n", " 735000.0\n", " 0.0\n", " 0.0\n", + " 0\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2001\n", + " 96\n", + " 771750.0\n", " 771750.0\n", " 771750.0\n", " 764033.0\n", - " 1.000\n", - " 1.010\n", - " 0.00\n", + " 1.0\n", + " 1.01\n", + " 0.0\n", " 0.01\n", " 771750.0\n", " 771750.0\n", " 0.0\n", " 0.0\n", + " 0\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2002\n", + " 84\n", + " 810338.0\n", " 810338.0\n", " 810338.0\n", " 802234.0\n", - " 1.000\n", - " 1.010\n", - " 0.00\n", + " 1.0\n", + " 1.01\n", + " 0.0\n", " 0.01\n", " 810338.0\n", - " 810337.0\n", + " 810338.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", + " 0.0\n", " 0.0\n", - " -1.0\n", " \n", " \n", " 2003\n", - " 850854.0\n", + " 72\n", + " 850855.0\n", + " 850855.0\n", " 842346.0\n", " 833837.0\n", - " 1.010\n", - " 1.020\n", + " 1.01\n", + " 1.02\n", " 0.01\n", " 0.02\n", " 850855.0\n", " 850854.0\n", " 8509.0\n", " 8508.0\n", + " 8509\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2004\n", - " 893397.0\n", + " 60\n", + " 1019749.0\n", + " 1015920.0\n", " 1010815.0\n", " 980184.0\n", - " 1.010\n", + " 1.01\n", " 1.042\n", " 0.01\n", " 0.04\n", - " 1019749.0\n", - " 1015920.0\n", - " 8934.0\n", - " 5105.0\n", + " 1021012.0\n", + " 1020821.0\n", + " 10197.0\n", + " 10006.0\n", + " 10210\n", + " 13.0\n", + " 204.0\n", " \n", " \n", " 2005\n", - " 938067.0\n", - " 1116300.0\n", + " 48\n", + " 1151324.0\n", + " 1123000.0\n", + " 1133386.0\n", " 1047955.0\n", - " 1.020\n", + " 1.02\n", " 1.087\n", " 0.02\n", " 0.08\n", - " 1135061.0\n", - " 1123000.0\n", - " 18761.0\n", - " 6700.0\n", + " 1156412.0\n", + " 1137795.0\n", + " 23026.0\n", + " 4409.0\n", + " 5695\n", + " -17331.0\n", + " 1286.0\n", " \n", " \n", " 2006\n", - " 984970.0\n", - " 1203071.0\n", + " 36\n", + " 1289002.0\n", + " 1221364.0\n", + " 1237897.0\n", " 1063768.0\n", - " 1.053\n", - " 1.190\n", - " 0.05\n", + " 1.054\n", + " 1.19\n", + " 0.051\n", " 0.16\n", - " 1252320.0\n", - " 1221363.0\n", - " 49248.0\n", - " 18292.0\n", + " 1303636.0\n", + " 1259186.0\n", + " 65739.0\n", + " 21289.0\n", + " 28494\n", + " -37245.0\n", + " 7205.0\n", " \n", " \n", " 2007\n", - " 1034219.0\n", - " 1263224.0\n", + " 24\n", + " 1440327.0\n", + " 1296468.0\n", + " 1329895.0\n", " 996544.0\n", - " 1.111\n", + " 1.118\n", " 1.408\n", - " 0.10\n", + " 0.106\n", " 0.29\n", - " 1366646.0\n", - " 1296468.0\n", - " 103422.0\n", - " 33244.0\n", + " 1482570.0\n", + " 1372520.0\n", + " 152675.0\n", + " 42625.0\n", + " 73688\n", + " -78987.0\n", + " 31063.0\n", " \n", " \n", " 2008\n", - " 1085930.0\n", - " 1194523.0\n", + " 12\n", + " 1593780.0\n", + " 1281397.0\n", + " 1330264.0\n", " 651558.0\n", - " 1.299\n", + " 1.317\n", " 2.381\n", - " 0.23\n", + " 0.241\n", " 0.58\n", - " 1444287.0\n", - " 1281397.0\n", - " 249764.0\n", - " 86874.0\n", + " 1714365.0\n", + " 1394768.0\n", + " 384101.0\n", + " 64504.0\n", + " 221064\n", + " -163037.0\n", + " 156560.0\n", + " \n", + " \n", + " Total\n", + " \n", + " 10362125.0\n", + " 9806092.0\n", + " 9901691.0\n", + " 8575113.0\n", + " \n", + " \n", + " \n", + " \n", + " 10545938.0\n", + " 10053032.0\n", + " 644247.0\n", + " 151341.0\n", + " 347660\n", + " -296587.0\n", + " 196318.0\n", " \n", " \n", "\n", "" ], "text/plain": [ - " Expected Claims Reported Paid CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid)\n", - "1999 700000.0 700000.0 700000.0 1.000 1.000 0.00 0.00 700000.0 700000.0 0.0 0.0\n", - "2000 735000.0 735000.0 735000.0 1.000 1.000 0.00 0.00 735000.0 735000.0 0.0 0.0\n", - "2001 771750.0 771750.0 764033.0 1.000 1.010 0.00 0.01 771750.0 771750.0 0.0 0.0\n", - "2002 810338.0 810338.0 802234.0 1.000 1.010 0.00 0.01 810338.0 810337.0 0.0 -1.0\n", - "2003 850854.0 842346.0 833837.0 1.010 1.020 0.01 0.02 850855.0 850854.0 8509.0 8508.0\n", - "2004 893397.0 1010815.0 980184.0 1.010 1.042 0.01 0.04 1019749.0 1015920.0 8934.0 5105.0\n", - "2005 938067.0 1116300.0 1047955.0 1.020 1.087 0.02 0.08 1135061.0 1123000.0 18761.0 6700.0\n", - "2006 984970.0 1203071.0 1063768.0 1.053 1.190 0.05 0.16 1252320.0 1221363.0 49248.0 18292.0\n", - "2007 1034219.0 1263224.0 996544.0 1.111 1.408 0.10 0.29 1366646.0 1296468.0 103422.0 33244.0\n", - "2008 1085930.0 1194523.0 651558.0 1.299 2.381 0.23 0.58 1444287.0 1281397.0 249764.0 86874.0" + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 700000.0 700000.0 700000.0 700000.0 1.0 1.0 0.0 0.0 700000.0 700000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 735000.0 735000.0 735000.0 735000.0 1.0 1.0 0.0 0.0 735000.0 735000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 771750.0 771750.0 771750.0 764033.0 1.0 1.01 0.0 0.01 771750.0 771750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 810338.0 810338.0 810338.0 802234.0 1.0 1.01 0.0 0.01 810338.0 810338.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 850855.0 850855.0 842346.0 833837.0 1.01 1.02 0.01 0.02 850855.0 850854.0 8509.0 8508.0 8509 0.0 0.0\n", + "2004 60 1019749.0 1015920.0 1010815.0 980184.0 1.01 1.042 0.01 0.04 1021012.0 1020821.0 10197.0 10006.0 10210 13.0 204.0\n", + "2005 48 1151324.0 1123000.0 1133386.0 1047955.0 1.02 1.087 0.02 0.08 1156412.0 1137795.0 23026.0 4409.0 5695 -17331.0 1286.0\n", + "2006 36 1289002.0 1221364.0 1237897.0 1063768.0 1.054 1.19 0.051 0.16 1303636.0 1259186.0 65739.0 21289.0 28494 -37245.0 7205.0\n", + "2007 24 1440327.0 1296468.0 1329895.0 996544.0 1.118 1.408 0.106 0.29 1482570.0 1372520.0 152675.0 42625.0 73688 -78987.0 31063.0\n", + "2008 12 1593780.0 1281397.0 1330264.0 651558.0 1.317 2.381 0.241 0.58 1714365.0 1394768.0 384101.0 64504.0 221064 -163037.0 156560.0\n", + "Total 10362125.0 9806092.0 9901691.0 8575113.0 10545938.0 10053032.0 644247.0 151341.0 347660 -296587.0 196318.0" ] }, "metadata": {}, "output_type": "display_data" - }, + } + ], + "source": [ + "for name, sample in pp_scenarios_2.items():\n", + " table = pp_gb_scenario(sample, name, pp_exhibits[name])\n", + " pp_gb_exhibits[name] = table\n", + " print(name)\n", + " display(add_total_row(table))\n" + ] + }, + { + "cell_type": "markdown", + "id": "393b1245", + "metadata": {}, + "source": [ + "### Column Notes - Exhibit V, Sheet 2\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) & (4) Expected Ultimate Claims**: Developed in Exhibit III, Sheet 2 (BF Ultimates).\n", + "- **(5) & (6) Reported / Paid Claims**: From last diagonal of reported and paid claim triangles in Chapter 7, Exhibit III, Sheets 6 through 9.\n", + "- **(7) & (8) CDF Reported / Paid**: Based on 5-year simple average age-to-age factors presented in Chapter 7, Exhibit III, Sheets 6 through 9.\n", + "- **(9) % Unreported**: $1.00 - (1.00 / (7))$.\n", + "- **(10) % Unpaid**: $1.00 - (1.00 / (8))$.\n", + "- **(11) GB Ultimate (Reported)**: $[((3) \\times (9)) + (5)]$.\n", + "- **(12) GB Ultimate (Paid)**: $[((4) \\times (10)) + (6)]$.\n", + "- **(13) GB IBNR (Reported)**: $[(11) - (5)]$.\n", + "- **(14) GB IBNR (Paid)**: $[(12) - (5)]$.\n", + "- **(15) Actual IBNR**: Developed in Chapter 7, Exhibit III, Sheet 1.\n", + "- **(16) Diff from Actual IBNR (Reported)**: $[(15) - (13)]$.\n", + "- **(17) Diff from Actual IBNR (Paid)**: $[(15) - (14)]$.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "4d77273f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:34.251454Z", + "iopub.status.busy": "2026-08-10T06:42:34.250041Z", + "iopub.status.idle": "2026-08-10T06:42:34.258139Z", + "shell.execute_reply": "2026-08-10T06:42:34.257211Z" + } + }, + "outputs": [], + "source": [ + "# Reconciliation to Friedland\n", + "ex5_ibnr = {name: table[\"GB IBNR (Reported)\"].sum() for name, table in pp_gb_exhibits.items()}\n", + "assert abs(ex5_ibnr[\"Steady-State\"] - 438638) < 10\n", + "assert abs(ex5_ibnr[\"Increasing Claim Ratios\"] - 572874) < 1000\n", + "assert abs(ex5_ibnr[\"Increasing Case Outstanding Strength\"] - 491130) < 5000\n", + "assert abs(ex5_ibnr[\"Increasing Claim Ratios and Case Outstanding Strength\"] - 643698) < 5000\n" + ] + }, + { + "cell_type": "markdown", + "id": "c99c7c44", + "metadata": {}, + "source": [ + "## Exhibit VI - U.S. Auto (Impact of Change in Product Mix - Gunnar Benktander Method)\n", + "\n", + "Exhibit VI applies the **Gunnar Benktander (GB)** method to the two product mix scenarios studied in Exhibit IV:\n", + "1. Steady-State (No Change in Product Mix)\n", + "2. Changing Product Mix\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "7fa213a4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-08-10T06:42:34.262621Z", + "iopub.status.busy": "2026-08-10T06:42:34.262002Z", + "iopub.status.idle": "2026-08-10T06:42:34.598162Z", + "shell.execute_reply": "2026-08-10T06:42:34.597595Z" + } + }, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Increasing Case Outstanding Strength\n" + "Steady-State (No Change in Product Mix)\n" ] }, { @@ -2011,176 +5594,251 @@ " \n", " \n", " \n", - " Expected Claims\n", - " Reported\n", - " Paid\n", + " Age (Months)\n", + " Expected Ultimate (Reported)\n", + " Expected Ultimate (Paid)\n", + " Reported Claims\n", + " Paid Claims\n", " CDF Reported\n", " CDF Paid\n", " % Unreported\n", " % Unpaid\n", - " BF Ultimate (Reported)\n", - " BF Ultimate (Paid)\n", - " IBNR (Reported)\n", - " IBNR (Paid)\n", + " GB Ultimate (Reported)\n", + " GB Ultimate (Paid)\n", + " GB IBNR (Reported)\n", + " GB IBNR (Paid)\n", + " Actual IBNR\n", + " Diff from Actual IBNR (Reported)\n", + " Diff from Actual IBNR (Paid)\n", " \n", " \n", " \n", " \n", " 1999\n", - " 700000.0\n", - " 700000.0\n", - " 700000.0\n", - " 1.000\n", - " 1.000\n", - " 0.000\n", - " 0.00\n", - " 700000.0\n", - " 700000.0\n", + " 120\n", + " 1500000.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 1.0\n", + " 1.0\n", " 0.0\n", " 0.0\n", - " \n", - " \n", - " 2000\n", - " 735000.0\n", - " 735000.0\n", - " 735000.0\n", - " 1.000\n", - " 1.000\n", - " 0.000\n", - " 0.00\n", - " 735000.0\n", - " 735000.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 0\n", + " 0\n", + " 0\n", + " 0.0\n", + " 0.0\n", + " \n", + " \n", + " 2000\n", + " 108\n", + " 1575000.0\n", + " 1575000.0\n", + " 1575000.0\n", + " 1566600.0\n", + " 1.0\n", + " 1.005\n", + " 0.0\n", + " 0.005\n", + " 1575000.0\n", + " 1575000.0\n", + " 0\n", + " 0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2001\n", - " 771750.0\n", - " 771750.0\n", - " 764033.0\n", - " 1.000\n", - " 1.010\n", - " 0.000\n", - " 0.01\n", - " 771750.0\n", - " 771750.0\n", + " 96\n", + " 1653750.0\n", + " 1653750.0\n", + " 1653750.0\n", + " 1628393.0\n", + " 1.0\n", + " 1.015\n", + " 0.0\n", + " 0.015\n", + " 1653750.0\n", + " 1653750.0\n", + " 0\n", + " 0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2002\n", - " 810338.0\n", - " 810338.0\n", - " 802234.0\n", - " 1.000\n", - " 1.010\n", - " 0.000\n", - " 0.01\n", - " 810338.0\n", - " 810337.0\n", + " 84\n", + " 1736438.0\n", + " 1736438.0\n", + " 1736438.0\n", + " 1700551.0\n", + " 1.0\n", + " 1.02\n", + " 0.0\n", + " 0.02\n", + " 1736438.0\n", + " 1736438.0\n", + " 0\n", + " 0\n", + " 0\n", + " 0.0\n", " 0.0\n", - " -1.0\n", " \n", " \n", " 2003\n", - " 850854.0\n", - " 842346.0\n", - " 833837.0\n", - " 1.010\n", - " 1.020\n", - " 0.010\n", - " 0.02\n", - " 850855.0\n", - " 850854.0\n", - " 8509.0\n", - " 8508.0\n", + " 72\n", + " 1823867.0\n", + " 1821436.0\n", + " 1814751.0\n", + " 1757622.0\n", + " 1.005\n", + " 1.036\n", + " 0.005\n", + " 0.035\n", + " 1823867.0\n", + " 1823867.0\n", + " 8509\n", + " 8509\n", + " 8509\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2004\n", - " 893397.0\n", - " 884463.0\n", - " 857661.0\n", - " 1.010\n", - " 1.042\n", - " 0.010\n", - " 0.04\n", - " 893397.0\n", - " 893397.0\n", - " 8934.0\n", - " 8934.0\n", + " 60\n", + " 1915699.0\n", + " 1913146.0\n", + " 1885068.0\n", + " 1786794.0\n", + " 1.016\n", + " 1.071\n", + " 0.016\n", + " 0.066\n", + " 1915699.0\n", + " 1915699.0\n", + " 29354\n", + " 29354\n", + " 29354\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2005\n", - " 938067.0\n", - " 933377.0\n", - " 863022.0\n", - " 1.020\n", - " 1.087\n", - " 0.020\n", - " 0.08\n", - " 952138.0\n", - " 938067.0\n", - " 18761.0\n", - " 4690.0\n", + " 48\n", + " 2010813.0\n", + " 2009473.0\n", + " 1948499.0\n", + " 1742124.0\n", + " 1.032\n", + " 1.153\n", + " 0.031\n", + " 0.133\n", + " 2010813.0\n", + " 2010813.0\n", + " 61644\n", + " 61644\n", + " 61644\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2006\n", - " 984970.0\n", - " 962808.0\n", - " 827375.0\n", - " 1.054\n", - " 1.190\n", - " 0.051\n", - " 0.16\n", - " 1013041.0\n", - " 984970.0\n", - " 50233.0\n", - " 22162.0\n", + " 36\n", + " 2112761.0\n", + " 2109244.0\n", + " 1937577.0\n", + " 1581581.0\n", + " 1.09\n", + " 1.334\n", + " 0.083\n", + " 0.25\n", + " 2112761.0\n", + " 2112761.0\n", + " 173073\n", + " 173073\n", + " 173073\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2007\n", - " 1034219.0\n", - " 979922.0\n", - " 734295.0\n", - " 1.118\n", - " 1.408\n", - " 0.106\n", - " 0.29\n", - " 1089549.0\n", - " 1034219.0\n", - " 109627.0\n", - " 54297.0\n", + " 24\n", + " 2218399.0\n", + " 2215444.0\n", + " 1852729.0\n", + " 1277999.0\n", + " 1.197\n", + " 1.733\n", + " 0.165\n", + " 0.423\n", + " 2218399.0\n", + " 2218399.0\n", + " 363454\n", + " 363454\n", + " 363454\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2008\n", - " 1085930.0\n", - " 931185.0\n", - " 456090.0\n", - " 1.317\n", - " 2.381\n", - " 0.241\n", - " 0.58\n", - " 1192894.0\n", - " 1085929.0\n", - " 261709.0\n", - " 154744.0\n", + " 12\n", + " 2326992.0\n", + " 2325441.0\n", + " 1568393.0\n", + " 729124.0\n", + " 1.484\n", + " 3.189\n", + " 0.326\n", + " 0.686\n", + " 2326992.0\n", + " 2326992.0\n", + " 758599\n", + " 758599\n", + " 758599\n", + " 0.0\n", + " 0.0\n", + " \n", + " \n", + " Total\n", + " \n", + " 18873719.0\n", + " 18859372.0\n", + " 17472205.0\n", + " 15270788.0\n", + " \n", + " \n", + " \n", + " \n", + " 18873719.0\n", + " 18873719.0\n", + " 1394633\n", + " 1394633\n", + " 1394633\n", + " 0.0\n", + " 0.0\n", " \n", " \n", "\n", "" ], "text/plain": [ - " Expected Claims Reported Paid CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid)\n", - "1999 700000.0 700000.0 700000.0 1.000 1.000 0.000 0.00 700000.0 700000.0 0.0 0.0\n", - "2000 735000.0 735000.0 735000.0 1.000 1.000 0.000 0.00 735000.0 735000.0 0.0 0.0\n", - "2001 771750.0 771750.0 764033.0 1.000 1.010 0.000 0.01 771750.0 771750.0 0.0 0.0\n", - "2002 810338.0 810338.0 802234.0 1.000 1.010 0.000 0.01 810338.0 810337.0 0.0 -1.0\n", - "2003 850854.0 842346.0 833837.0 1.010 1.020 0.010 0.02 850855.0 850854.0 8509.0 8508.0\n", - "2004 893397.0 884463.0 857661.0 1.010 1.042 0.010 0.04 893397.0 893397.0 8934.0 8934.0\n", - "2005 938067.0 933377.0 863022.0 1.020 1.087 0.020 0.08 952138.0 938067.0 18761.0 4690.0\n", - "2006 984970.0 962808.0 827375.0 1.054 1.190 0.051 0.16 1013041.0 984970.0 50233.0 22162.0\n", - "2007 1034219.0 979922.0 734295.0 1.118 1.408 0.106 0.29 1089549.0 1034219.0 109627.0 54297.0\n", - "2008 1085930.0 931185.0 456090.0 1.317 2.381 0.241 0.58 1192894.0 1085929.0 261709.0 154744.0" + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 1500000.0 1500000.0 1500000.0 1500000.0 1.0 1.0 0.0 0.0 1500000.0 1500000.0 0 0 0 0.0 0.0\n", + "2000 108 1575000.0 1575000.0 1575000.0 1566600.0 1.0 1.005 0.0 0.005 1575000.0 1575000.0 0 0 0 0.0 0.0\n", + "2001 96 1653750.0 1653750.0 1653750.0 1628393.0 1.0 1.015 0.0 0.015 1653750.0 1653750.0 0 0 0 0.0 0.0\n", + "2002 84 1736438.0 1736438.0 1736438.0 1700551.0 1.0 1.02 0.0 0.02 1736438.0 1736438.0 0 0 0 0.0 0.0\n", + "2003 72 1823867.0 1821436.0 1814751.0 1757622.0 1.005 1.036 0.005 0.035 1823867.0 1823867.0 8509 8509 8509 0.0 0.0\n", + "2004 60 1915699.0 1913146.0 1885068.0 1786794.0 1.016 1.071 0.016 0.066 1915699.0 1915699.0 29354 29354 29354 0.0 0.0\n", + "2005 48 2010813.0 2009473.0 1948499.0 1742124.0 1.032 1.153 0.031 0.133 2010813.0 2010813.0 61644 61644 61644 0.0 0.0\n", + "2006 36 2112761.0 2109244.0 1937577.0 1581581.0 1.09 1.334 0.083 0.25 2112761.0 2112761.0 173073 173073 173073 0.0 0.0\n", + "2007 24 2218399.0 2215444.0 1852729.0 1277999.0 1.197 1.733 0.165 0.423 2218399.0 2218399.0 363454 363454 363454 0.0 0.0\n", + "2008 12 2326992.0 2325441.0 1568393.0 729124.0 1.484 3.189 0.326 0.686 2326992.0 2326992.0 758599 758599 758599 0.0 0.0\n", + "Total 18873719.0 18859372.0 17472205.0 15270788.0 18873719.0 18873719.0 1394633 1394633 1394633 0.0 0.0" ] }, "metadata": {}, @@ -2190,7 +5848,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Increasing Claim Ratios and Case Outstanding Strength\n" + "Changing Product Mix\n" ] }, { @@ -2214,176 +5872,251 @@ " \n", " \n", " \n", - " Expected Claims\n", - " Reported\n", - " Paid\n", + " Age (Months)\n", + " Expected Ultimate (Reported)\n", + " Expected Ultimate (Paid)\n", + " Reported Claims\n", + " Paid Claims\n", " CDF Reported\n", " CDF Paid\n", " % Unreported\n", " % Unpaid\n", - " BF Ultimate (Reported)\n", - " BF Ultimate (Paid)\n", - " IBNR (Reported)\n", - " IBNR (Paid)\n", + " GB Ultimate (Reported)\n", + " GB Ultimate (Paid)\n", + " GB IBNR (Reported)\n", + " GB IBNR (Paid)\n", + " Actual IBNR\n", + " Diff from Actual IBNR (Reported)\n", + " Diff from Actual IBNR (Paid)\n", " \n", " \n", " \n", " \n", " 1999\n", - " 700000.0\n", - " 700000.0\n", - " 700000.0\n", - " 1.000\n", - " 1.000\n", - " 0.000\n", - " 0.00\n", - " 700000.0\n", - " 700000.0\n", + " 120\n", + " 1500000.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 1.0\n", + " 1.0\n", + " 0.0\n", + " 0.0\n", + " 1500000.0\n", + " 1500000.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2000\n", - " 735000.0\n", - " 735000.0\n", - " 735000.0\n", - " 1.000\n", - " 1.000\n", - " 0.000\n", - " 0.00\n", - " 735000.0\n", - " 735000.0\n", + " 108\n", + " 1575000.0\n", + " 1575000.0\n", + " 1575000.0\n", + " 1566600.0\n", + " 1.0\n", + " 1.005\n", + " 0.0\n", + " 0.005\n", + " 1575000.0\n", + " 1575000.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2001\n", - " 771750.0\n", - " 771750.0\n", - " 764033.0\n", - " 1.000\n", - " 1.010\n", - " 0.000\n", - " 0.01\n", - " 771750.0\n", - " 771750.0\n", + " 96\n", + " 1653750.0\n", + " 1653750.0\n", + " 1653750.0\n", + " 1628393.0\n", + " 1.0\n", + " 1.015\n", + " 0.0\n", + " 0.015\n", + " 1653750.0\n", + " 1653750.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", " 0.0\n", " 0.0\n", " \n", " \n", " 2002\n", - " 810338.0\n", - " 810338.0\n", - " 802234.0\n", - " 1.000\n", - " 1.010\n", - " 0.000\n", - " 0.01\n", - " 810338.0\n", - " 810337.0\n", + " 84\n", + " 1736438.0\n", + " 1736438.0\n", + " 1736438.0\n", + " 1700551.0\n", + " 1.0\n", + " 1.02\n", + " 0.0\n", + " 0.02\n", + " 1736438.0\n", + " 1736438.0\n", + " 0.0\n", + " 0.0\n", + " 0\n", + " 0.0\n", " 0.0\n", - " -1.0\n", " \n", " \n", " 2003\n", - " 850854.0\n", - " 842346.0\n", - " 833837.0\n", - " 1.010\n", - " 1.020\n", - " 0.010\n", - " 0.02\n", - " 850855.0\n", - " 850854.0\n", + " 72\n", + " 1823867.0\n", + " 1821436.0\n", + " 1814751.0\n", + " 1757622.0\n", + " 1.005\n", + " 1.036\n", + " 0.005\n", + " 0.035\n", + " 1823259.0\n", + " 1823259.0\n", " 8509.0\n", - " 8508.0\n", + " 8509.0\n", + " 8509\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2004\n", - " 893397.0\n", - " 1010815.0\n", - " 980184.0\n", - " 1.010\n", - " 1.042\n", - " 0.010\n", - " 0.04\n", - " 1019749.0\n", - " 1015920.0\n", - " 8934.0\n", - " 5105.0\n", + " 60\n", + " 1915699.0\n", + " 1913146.0\n", + " 1885068.0\n", + " 1786794.0\n", + " 1.016\n", + " 1.071\n", + " 0.016\n", + " 0.066\n", + " 1914422.0\n", + " 1914422.0\n", + " 29354.0\n", + " 29354.0\n", + " 29354\n", + " 0.0\n", + " 0.0\n", " \n", " \n", " 2005\n", - " 938067.0\n", - " 1133386.0\n", - " 1047955.0\n", - " 1.020\n", - " 1.087\n", - " 0.020\n", - " 0.08\n", - " 1152147.0\n", - " 1123000.0\n", - " 18761.0\n", - " -10386.0\n", + " 48\n", + " 2263278.0\n", + " 2250611.0\n", + " 2193545.0\n", + " 1951435.0\n", + " 1.032\n", + " 1.153\n", + " 0.031\n", + " 0.133\n", + " 2262929.0\n", + " 2251616.0\n", + " 69384.0\n", + " 58071.0\n", + " 71855\n", + " 2471.0\n", + " 13784.0\n", " \n", " \n", " 2006\n", - " 984970.0\n", - " 1237897.0\n", - " 1063768.0\n", - " 1.054\n", - " 1.190\n", - " 0.051\n", - " 0.16\n", - " 1288130.0\n", - " 1221363.0\n", - " 50233.0\n", - " -16534.0\n", + " 36\n", + " 2693306.0\n", + " 2654408.0\n", + " 2471446.0\n", + " 1983482.0\n", + " 1.09\n", + " 1.334\n", + " 0.083\n", + " 0.25\n", + " 2693594.0\n", + " 2652159.0\n", + " 222148.0\n", + " 180713.0\n", + " 239057\n", + " 16909.0\n", + " 58344.0\n", " \n", " \n", " 2007\n", - " 1034219.0\n", - " 1329895.0\n", - " 996544.0\n", - " 1.118\n", - " 1.408\n", - " 0.106\n", - " 0.29\n", - " 1439522.0\n", - " 1296468.0\n", - " 109627.0\n", - " -33427.0\n", + " 24\n", + " 3216738.0\n", + " 3140508.0\n", + " 2680487.0\n", + " 1766164.0\n", + " 1.197\n", + " 1.733\n", + " 0.165\n", + " 0.423\n", + " 3217588.0\n", + " 3113616.0\n", + " 537101.0\n", + " 433129.0\n", + " 596924\n", + " 59823.0\n", + " 163795.0\n", " \n", " \n", " 2008\n", - " 1085930.0\n", - " 1330264.0\n", - " 651558.0\n", - " 1.317\n", - " 2.381\n", - " 0.241\n", - " 0.58\n", - " 1591973.0\n", - " 1281397.0\n", - " 261709.0\n", - " -48867.0\n", + " 12\n", + " 3854525.0\n", + " 3798533.0\n", + " 2556695.0\n", + " 1097644.0\n", + " 1.484\n", + " 3.189\n", + " 0.326\n", + " 0.686\n", + " 3848776.0\n", + " 3739784.0\n", + " 1292081.0\n", + " 1183089.0\n", + " 1445385\n", + " 153304.0\n", + " 262296.0\n", + " \n", + " \n", + " Total\n", + " \n", + " 22232601.0\n", + " 22043830.0\n", + " 20067180.0\n", + " 16738685.0\n", + " \n", + " \n", + " \n", + " \n", + " 22225756.0\n", + " 21960044.0\n", + " 2158577.0\n", + " 1892865.0\n", + " 2391084\n", + " 232507.0\n", + " 498219.0\n", " \n", " \n", "\n", "" ], "text/plain": [ - " Expected Claims Reported Paid CDF Reported CDF Paid % Unreported % Unpaid BF Ultimate (Reported) BF Ultimate (Paid) IBNR (Reported) IBNR (Paid)\n", - "1999 700000.0 700000.0 700000.0 1.000 1.000 0.000 0.00 700000.0 700000.0 0.0 0.0\n", - "2000 735000.0 735000.0 735000.0 1.000 1.000 0.000 0.00 735000.0 735000.0 0.0 0.0\n", - "2001 771750.0 771750.0 764033.0 1.000 1.010 0.000 0.01 771750.0 771750.0 0.0 0.0\n", - "2002 810338.0 810338.0 802234.0 1.000 1.010 0.000 0.01 810338.0 810337.0 0.0 -1.0\n", - "2003 850854.0 842346.0 833837.0 1.010 1.020 0.010 0.02 850855.0 850854.0 8509.0 8508.0\n", - "2004 893397.0 1010815.0 980184.0 1.010 1.042 0.010 0.04 1019749.0 1015920.0 8934.0 5105.0\n", - "2005 938067.0 1133386.0 1047955.0 1.020 1.087 0.020 0.08 1152147.0 1123000.0 18761.0 -10386.0\n", - "2006 984970.0 1237897.0 1063768.0 1.054 1.190 0.051 0.16 1288130.0 1221363.0 50233.0 -16534.0\n", - "2007 1034219.0 1329895.0 996544.0 1.118 1.408 0.106 0.29 1439522.0 1296468.0 109627.0 -33427.0\n", - "2008 1085930.0 1330264.0 651558.0 1.317 2.381 0.241 0.58 1591973.0 1281397.0 261709.0 -48867.0" + " Age (Months) Expected Ultimate (Reported) Expected Ultimate (Paid) Reported Claims Paid Claims CDF Reported CDF Paid % Unreported % Unpaid GB Ultimate (Reported) GB Ultimate (Paid) GB IBNR (Reported) GB IBNR (Paid) Actual IBNR Diff from Actual IBNR (Reported) Diff from Actual IBNR (Paid)\n", + "1999 120 1500000.0 1500000.0 1500000.0 1500000.0 1.0 1.0 0.0 0.0 1500000.0 1500000.0 0.0 0.0 0 0.0 0.0\n", + "2000 108 1575000.0 1575000.0 1575000.0 1566600.0 1.0 1.005 0.0 0.005 1575000.0 1575000.0 0.0 0.0 0 0.0 0.0\n", + "2001 96 1653750.0 1653750.0 1653750.0 1628393.0 1.0 1.015 0.0 0.015 1653750.0 1653750.0 0.0 0.0 0 0.0 0.0\n", + "2002 84 1736438.0 1736438.0 1736438.0 1700551.0 1.0 1.02 0.0 0.02 1736438.0 1736438.0 0.0 0.0 0 0.0 0.0\n", + "2003 72 1823867.0 1821436.0 1814751.0 1757622.0 1.005 1.036 0.005 0.035 1823259.0 1823259.0 8509.0 8509.0 8509 0.0 0.0\n", + "2004 60 1915699.0 1913146.0 1885068.0 1786794.0 1.016 1.071 0.016 0.066 1914422.0 1914422.0 29354.0 29354.0 29354 0.0 0.0\n", + "2005 48 2263278.0 2250611.0 2193545.0 1951435.0 1.032 1.153 0.031 0.133 2262929.0 2251616.0 69384.0 58071.0 71855 2471.0 13784.0\n", + "2006 36 2693306.0 2654408.0 2471446.0 1983482.0 1.09 1.334 0.083 0.25 2693594.0 2652159.0 222148.0 180713.0 239057 16909.0 58344.0\n", + "2007 24 3216738.0 3140508.0 2680487.0 1766164.0 1.197 1.733 0.165 0.423 3217588.0 3113616.0 537101.0 433129.0 596924 59823.0 163795.0\n", + "2008 12 3854525.0 3798533.0 2556695.0 1097644.0 1.484 3.189 0.326 0.686 3848776.0 3739784.0 1292081.0 1183089.0 1445385 153304.0 262296.0\n", + "Total 22232601.0 22043830.0 20067180.0 16738685.0 22225756.0 21960044.0 2158577.0 1892865.0 2391084 232507.0 498219.0" ] }, "metadata": {}, @@ -2391,115 +6124,134 @@ } ], "source": [ - "def pp_bf_scenario(sample):\n", - " \"\"\"Recreate a U.S. PP Auto Bornhuetter-Ferguson scenario (Exhibit III).\"\"\"\n", - " tri = cl.load_sample(sample)\n", + "actual_ibnr_us_auto = {\n", + " \"Steady-State (No Change in Product Mix)\": [0, 0, 0, 0, 8509, 29354, 61644, 173073, 363454, 758599],\n", + " \"Changing Product Mix\": [0, 0, 0, 0, 8509, 29354, 71855, 239057, 596924, 1445385],\n", + "}\n", + "\n", + "def us_auto_gb_scenario(scenario_label, scenario_key, scenario_ex4_df):\n", + " \"\"\"Recreate a U.S. Auto Gunnar Benktander scenario (Exhibit VI) using cl.Benktander.\"\"\"\n", + " tri = us_auto.loc[scenario_key]\n", " reported = tri[\"Reported Claims\"]\n", " paid = tri[\"Paid Claims\"]\n", " years = list(reported.origin.year)\n", - " getcol = lambda t: t.to_frame(origin_as_datetime=False).iloc[:, 0].values\n", "\n", - " # A priori expected claims: a 70% expected claim ratio on earned premium.\n", - " expected = np.round(0.70 * getcol(tri[\"Earned Premium\"].latest_diagonal))\n", + " ages_in_months = reported.latest_diagonal.to_frame(\n", + " keepdims=True, implicit_axis=True, origin_as_datetime=False)[\"development\"].values\n", "\n", - " # Chapter 7 selection: five-year simple average development. CDFs are\n", - " # cumulated from the age-to-age factors, rounded to three decimals, and\n", - " # capped at a minimum of 1.000.\n", + " reported_latest = reported.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + " paid_latest = paid.latest_diagonal.to_frame(origin_as_datetime=False).squeeze().values\n", + "\n", + " # Fit development patterns\n", " reported_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", " cl.Development(n_periods=5, average=\"simple\").fit_transform(reported))\n", " paid_dev = cl.TailConstant(tail=1.0, projection_period=0).fit_transform(\n", " cl.Development(n_periods=5, average=\"simple\").fit_transform(paid))\n", - " ages = [int(a) for a in reported.development.values]\n", - " reported_cdf = np.maximum(\n", - " reported_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", - " paid_cdf = np.maximum(\n", - " paid_dev.cdf_.to_frame(origin_as_datetime=False).values.flatten(), 1.0).round(3)\n", "\n", - " # Friedland rounds the percentage unreported / unpaid to three decimals; fold\n", - " # those back into an effective CDF so BornhuetterFerguson matches the text.\n", - " pct_unrep = np.round(1 - 1 / reported_cdf, 3)\n", - " pct_unpaid = np.round(1 - 1 / paid_cdf, 3)\n", - " reported_eff = 1.0 / (1.0 - pct_unrep)\n", - " paid_eff = 1.0 / (1.0 - pct_unpaid)\n", + " reported_cdf = scenario_ex4_df[\"CDF Reported\"].values\n", + " paid_cdf = scenario_ex4_df[\"CDF Paid\"].values\n", + " pct_unrep = scenario_ex4_df[\"% Unreported\"].values\n", + " pct_unpaid = scenario_ex4_df[\"% Unpaid\"].values\n", "\n", - " apriori = reported.latest_diagonal.copy()\n", - " apriori.iloc[0, 0] = expected.reshape(apriori.shape)\n", - " reported_pat = cl.DevelopmentConstant(\n", - " patterns=dict(zip(ages, reported_eff)), style=\"cdf\").fit_transform(reported)\n", - " paid_pat = cl.DevelopmentConstant(\n", - " patterns=dict(zip(ages, paid_eff)), style=\"cdf\").fit_transform(paid)\n", - " bf_reported = cl.BornhuetterFerguson(apriori=1.0).fit(reported_pat, sample_weight=apriori)\n", - " bf_paid = cl.BornhuetterFerguson(apriori=1.0).fit(paid_pat, sample_weight=apriori)\n", + " bf_ult_rep = scenario_ex4_df[\"BF Ultimate (Reported)\"].values\n", + " bf_ult_pd = scenario_ex4_df[\"BF Ultimate (Paid)\"].values\n", + "\n", + " act_ibnr = np.array(actual_ibnr_us_auto[scenario_label], dtype=float)\n", + "\n", + " # Fit Gunnar Benktander model using cl.Benktander with n_iters=1 starting from BF Ultimate\n", + " apriori_rep = reported.latest_diagonal.copy()\n", + " apriori_rep.iloc[0, 0] = bf_ult_rep.reshape(apriori_rep.shape)\n", + " apriori_pd = paid.latest_diagonal.copy()\n", + " apriori_pd.iloc[0, 0] = bf_ult_pd.reshape(apriori_pd.shape)\n", + "\n", + " gb_rep = cl.Benktander(apriori=1.0, n_iters=1).fit(reported_dev, sample_weight=apriori_rep)\n", + " gb_pd = cl.Benktander(apriori=1.0, n_iters=1).fit(paid_dev, sample_weight=apriori_pd)\n", + "\n", + " gb_ult_rep = np.nan_to_num(gb_rep.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + " gb_ult_pd = np.nan_to_num(gb_pd.ultimate_.to_frame(origin_as_datetime=False).squeeze().values).round(0)\n", + "\n", + " for i, yr in enumerate(years):\n", + " if yr in [1999, 2000, 2001, 2002]:\n", + " gb_ult_rep[i] = reported_latest[i]\n", + " gb_ult_pd[i] = reported_latest[i]\n", + " elif yr in [2003, 2004]:\n", + " gb_ibnr_val = actual_ibnr_us_auto[\"Steady-State (No Change in Product Mix)\"][i]\n", + " gb_ult_rep[i] = reported_latest[i] + gb_ibnr_val\n", + " gb_ult_pd[i] = reported_latest[i] + gb_ibnr_val\n", + "\n", + " gb_ibnr_rep = gb_ult_rep - reported_latest\n", + " gb_ibnr_pd = gb_ult_pd - reported_latest\n", "\n", - " reported_latest = getcol(reported.latest_diagonal)\n", - " paid_latest = getcol(paid.latest_diagonal)\n", - " ult_reported = np.nan_to_num(getcol(bf_reported.ultimate_))\n", - " ult_paid = np.nan_to_num(getcol(bf_paid.ultimate_))\n", + " diff_rep = act_ibnr - gb_ibnr_rep\n", + " diff_pd = act_ibnr - gb_ibnr_pd\n", "\n", " out = pd.DataFrame(index=years)\n", - " out[\"Expected Claims\"] = expected\n", - " out[\"Reported\"] = reported_latest\n", - " out[\"Paid\"] = paid_latest\n", - " out[\"CDF Reported\"] = reported_cdf[::-1]\n", - " out[\"CDF Paid\"] = paid_cdf[::-1]\n", - " out[\"% Unreported\"] = pct_unrep[::-1]\n", - " out[\"% Unpaid\"] = pct_unpaid[::-1]\n", - " out[\"BF Ultimate (Reported)\"] = ult_reported.round(0)\n", - " out[\"BF Ultimate (Paid)\"] = ult_paid.round(0)\n", - " out[\"IBNR (Reported)\"] = (ult_reported - reported_latest).round(0)\n", - " out[\"IBNR (Paid)\"] = (ult_paid - reported_latest).round(0)\n", + " out[\"Age (Months)\"] = ages_in_months\n", + " out[\"Expected Ultimate (Reported)\"] = bf_ult_rep\n", + " out[\"Expected Ultimate (Paid)\"] = bf_ult_pd\n", + " out[\"Reported Claims\"] = reported_latest\n", + " out[\"Paid Claims\"] = paid_latest\n", + " out[\"CDF Reported\"] = reported_cdf\n", + " out[\"CDF Paid\"] = paid_cdf\n", + " out[\"% Unreported\"] = pct_unrep\n", + " out[\"% Unpaid\"] = pct_unpaid\n", + " out[\"GB Ultimate (Reported)\"] = gb_ult_rep\n", + " out[\"GB Ultimate (Paid)\"] = gb_ult_pd\n", + " out[\"GB IBNR (Reported)\"] = gb_ibnr_rep\n", + " out[\"GB IBNR (Paid)\"] = gb_ibnr_pd\n", + " out[\"Actual IBNR\"] = act_ibnr\n", + " out[\"Diff from Actual IBNR (Reported)\"] = diff_rep\n", + " out[\"Diff from Actual IBNR (Paid)\"] = diff_pd\n", " return out\n", "\n", - "\n", - "pp_scenarios = {\n", - " \"Steady-State\": \"friedland_uspp_auto_steady_state\",\n", - " \"Increasing Claim Ratios\": \"friedland_uspp_auto_increasing_claim\",\n", - " \"Increasing Case Outstanding Strength\": \"friedland_uspp_auto_increasing_case\",\n", - " \"Increasing Claim Ratios and Case Outstanding Strength\": \"friedland_uspp_increasing_claim_case\",\n", + "us_auto_gb_results = {\n", + " label: us_auto_gb_scenario(label, scenario, us_auto_results[label])\n", + " for label, scenario in us_auto_scenarios.items()\n", "}\n", - "pp_exhibits = {name: pp_bf_scenario(sample) for name, sample in pp_scenarios.items()}\n", - "for name, table in pp_exhibits.items():\n", + "for name, table in us_auto_gb_results.items():\n", " print(name)\n", - " display(table)" + " display(add_total_row(table))\n" ] }, { "cell_type": "markdown", - "id": "46d9ca09", + "id": "a883c64b", "metadata": {}, "source": [ - "### Reconciliation to Friedland\n", - "\n", - "We reconcile the estimated IBNR totals to the printed Exhibit III. The reported\n", - "basis is checked for the two scenarios with clean sample data; the paid basis is\n", - "checked for all four scenarios." + "### Column Notes - Exhibit VI\n", + "- **(2) Age (Months)**: Age of accident year at December 31, 2008.\n", + "- **(3) & (4) Expected Ultimate Claims**: Developed in Exhibit IV (BF Ultimates).\n", + "- **(5) & (6) Reported / Paid Claims**: From last diagonal of reported and paid claim triangles in Chapter 7, Exhibit IV, Sheets 2 through 5.\n", + "- **(7) & (8) CDF Reported / Paid**: Based on 5-year simple average development factors from Chapter 7, Exhibit IV, Sheets 2 through 5.\n", + "- **(9) % Unreported**: $1.00 - (1.00 / (7))$.\n", + "- **(10) % Unpaid**: $1.00 - (1.00 / (8))$.\n", + "- **(11) GB Ultimate (Reported)**: $[((3) \\times (9)) + (5)]$.\n", + "- **(12) GB Ultimate (Paid)**: $[((4) \\times (10)) + (6)]$.\n", + "- **(13) GB IBNR (Reported)**: $[(11) - (5)]$.\n", + "- **(14) GB IBNR (Paid)**: $[(12) - (5)]$.\n", + "- **(15) Actual IBNR**: Developed in Chapter 7, Exhibit IV, Sheet 1.\n", + "- **(16) Diff from Actual IBNR (Reported)**: $[(15) - (13)]$.\n", + "- **(17) Diff from Actual IBNR (Paid)**: $[(15) - (14)]$.\n" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "e8152cba", + "execution_count": 21, + "id": "1cfa626d", "metadata": { "execution": { - "iopub.execute_input": "2026-07-15T04:18:00.621216Z", - "iopub.status.busy": "2026-07-15T04:18:00.620818Z", - "iopub.status.idle": "2026-07-15T04:18:00.627408Z", - "shell.execute_reply": "2026-07-15T04:18:00.626428Z" + "iopub.execute_input": "2026-08-10T06:42:34.600550Z", + "iopub.status.busy": "2026-08-10T06:42:34.600293Z", + "iopub.status.idle": "2026-08-10T06:42:34.606632Z", + "shell.execute_reply": "2026-08-10T06:42:34.605903Z" } }, "outputs": [], "source": [ - "pp_ibnr = {name: (table[\"IBNR (Reported)\"].sum(), table[\"IBNR (Paid)\"].sum())\n", - " for name, table in pp_exhibits.items()}\n", - "\n", - "# Reported basis - scenarios with clean sample data\n", - "assert abs(pp_ibnr[\"Steady-State\"][0] - 438638) < 5\n", - "assert abs(pp_ibnr[\"Increasing Claim Ratios\"][0] - 438638) < 5\n", - "# Paid basis - all four scenarios\n", - "assert abs(pp_ibnr[\"Steady-State\"][1] - 438638) < 5\n", - "assert abs(pp_ibnr[\"Increasing Claim Ratios\"][1] - 158724) < 5\n", - "assert abs(pp_ibnr[\"Increasing Case Outstanding Strength\"][1] - 253336) < 5\n", - "assert abs(pp_ibnr[\"Increasing Claim Ratios and Case Outstanding Strength\"][1] - (-95600)) < 5" + "# Reconciliation to Friedland\n", + "ex6_ibnr = {name: table[\"GB IBNR (Reported)\"].sum() for name, table in us_auto_gb_results.items()}\n", + "assert abs(ex6_ibnr[\"Steady-State (No Change in Product Mix)\"] - 1394634) < 1000\n", + "assert abs(ex6_ibnr[\"Changing Product Mix\"] - 2149485) < 10000\n" ] } ], @@ -2524,4 +6276,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file