Working with Triangles¶
Getting Started¶
Welcome! We drafted these tutorials to help you get familiar with some of the common functionalities that most actuaries can use in their day-to-day responsibilities. The package also comes with pre-installed datasets that you can play with, which are also used in the tutorials here.
The tutorials assume that you have the basic understanding of commonly used actuarial terms, and can independently perform an actuarial analysis in another tool, such as Microsoft Excel or another actuarial software. Furthermore, it is assumed that you already have some familiarity with Python, and that you have the basic knowledge and experience in using some common packages that are popular in the Python community, such as pandas
and numpy
.
This tutorial is linted using black via nb_black. This step is optional.
%load_ext lab_black
All tutorials and exercises rely on chainladder v0.8.12 and later. It is highly recomended that you keep your packages up-to-date.
For more info on how to update your pakages, visit Keeping Packages Updated.
import pandas as pd
import numpy as np
import chainladder as cl
print("pandas: " + pd.__version__)
print("numpy: " + np.__version__)
print("chainladder: " + cl.__version__)
pandas: 1.5.3
numpy: 1.24.3
chainladder: 0.8.16
Since we will be plotting for quite a bit, here’s a magic function in IPython, which sets the backend of matplotlib to the ‘inline’ backend. With this backend, the output of plotting commands is displayed inline within frontends like the Jupyter notebook, directly below the code cell that produced it. The resulting plots will then also be stored in the notebook document.
%matplotlib inline
Disclaimer¶
Note that a lot of the examples shown might not be applicable in a real world scenario, and is only meant to demonstrate some of the functionalities included in the package. The user should always follow all applicable laws, the Code of Professional Conduct, applicable Actuarial Standards of Practice, and exercise their best actuarial judgement.
Working with a Triangle¶
Let’s begin by looking at an unprocessed triangle data and load it into a pandas.DataFrame
. We’ll use the data raa
, which is available from the repository.
raa_df = pd.read_csv(
"https://raw.githubusercontent.com/casact/chainladder-python/master/chainladder/utils/data/raa.csv"
)
raa_df.head(20)
development | origin | values | |
---|---|---|---|
0 | 1981 | 1981 | 5012.0 |
1 | 1982 | 1982 | 106.0 |
2 | 1983 | 1983 | 3410.0 |
3 | 1984 | 1984 | 5655.0 |
4 | 1985 | 1985 | 1092.0 |
5 | 1986 | 1986 | 1513.0 |
6 | 1987 | 1987 | 557.0 |
7 | 1988 | 1988 | 1351.0 |
8 | 1989 | 1989 | 3133.0 |
9 | 1990 | 1990 | 2063.0 |
10 | 1982 | 1981 | 8269.0 |
11 | 1983 | 1982 | 4285.0 |
12 | 1984 | 1983 | 8992.0 |
13 | 1985 | 1984 | 11555.0 |
14 | 1986 | 1985 | 9565.0 |
15 | 1987 | 1986 | 6445.0 |
16 | 1988 | 1987 | 4020.0 |
17 | 1989 | 1988 | 6947.0 |
18 | 1990 | 1989 | 5395.0 |
19 | 1983 | 1981 | 10907.0 |
The data has three columns:
development: or valuation time, in this case, valuation year
origin: or accident date, in this case, accident year
values: the values recorded for the specific accident date at the specific valuation time (such as incurred losses, paid losses, or claim counts)
A table of loss experience showing total losses for a certain period (origin) at various, regular valuation dates (development), reflect the change in amounts as claims mature and emerge. Older periods in the table will have one more entry than the next youngest period, leading to the triangle shape of the data in the table or any other measure that matures over time from an origin date. Loss triangles can be used to determine loss development for a given risk.
Let’s put our data into the triangle format.
raa = cl.Triangle(
raa_df,
origin="origin",
development="development",
columns="values",
cumulative=True,
)
raa
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1981 | 5,012 | 8,269 | 10,907 | 11,805 | 13,539 | 16,181 | 18,009 | 18,608 | 18,662 | 18,834 |
1982 | 106 | 4,285 | 5,396 | 10,666 | 13,782 | 15,599 | 15,496 | 16,169 | 16,704 | |
1983 | 3,410 | 8,992 | 13,873 | 16,141 | 18,735 | 22,214 | 22,863 | 23,466 | ||
1984 | 5,655 | 11,555 | 15,766 | 21,266 | 23,425 | 26,083 | 27,067 | |||
1985 | 1,092 | 9,565 | 15,836 | 22,169 | 25,955 | 26,180 | ||||
1986 | 1,513 | 6,445 | 11,702 | 12,935 | 15,852 | |||||
1987 | 557 | 4,020 | 10,946 | 12,314 | ||||||
1988 | 1,351 | 6,947 | 13,112 | |||||||
1989 | 3,133 | 5,395 | ||||||||
1990 | 2,063 |
You can also load the example data directly, using load_sample
:
raa = cl.load_sample("raa")
raa
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1981 | 5,012 | 8,269 | 10,907 | 11,805 | 13,539 | 16,181 | 18,009 | 18,608 | 18,662 | 18,834 |
1982 | 106 | 4,285 | 5,396 | 10,666 | 13,782 | 15,599 | 15,496 | 16,169 | 16,704 | |
1983 | 3,410 | 8,992 | 13,873 | 16,141 | 18,735 | 22,214 | 22,863 | 23,466 | ||
1984 | 5,655 | 11,555 | 15,766 | 21,266 | 23,425 | 26,083 | 27,067 | |||
1985 | 1,092 | 9,565 | 15,836 | 22,169 | 25,955 | 26,180 | ||||
1986 | 1,513 | 6,445 | 11,702 | 12,935 | 15,852 | |||||
1987 | 557 | 4,020 | 10,946 | 12,314 | ||||||
1988 | 1,351 | 6,947 | 13,112 | |||||||
1989 | 3,133 | 5,395 | ||||||||
1990 | 2,063 |
A triangle has more properties than just what is displayed. For example we can see the underlying link_ratio
s, which represent the multiplicative change in amounts from one development period to the next.
raa.link_ratio
12-24 | 24-36 | 36-48 | 48-60 | 60-72 | 72-84 | 84-96 | 96-108 | 108-120 | |
---|---|---|---|---|---|---|---|---|---|
1981 | 1.6498 | 1.3190 | 1.0823 | 1.1469 | 1.1951 | 1.1130 | 1.0333 | 1.0029 | 1.0092 |
1982 | 40.4245 | 1.2593 | 1.9766 | 1.2921 | 1.1318 | 0.9934 | 1.0434 | 1.0331 | |
1983 | 2.6370 | 1.5428 | 1.1635 | 1.1607 | 1.1857 | 1.0292 | 1.0264 | ||
1984 | 2.0433 | 1.3644 | 1.3489 | 1.1015 | 1.1135 | 1.0377 | |||
1985 | 8.7592 | 1.6556 | 1.3999 | 1.1708 | 1.0087 | ||||
1986 | 4.2597 | 1.8157 | 1.1054 | 1.2255 | |||||
1987 | 7.2172 | 2.7229 | 1.1250 | ||||||
1988 | 5.1421 | 1.8874 | |||||||
1989 | 1.7220 |
We can also view (and manipulate) the latest_diagonal
of the triangle.
raa.latest_diagonal
1990 | |
---|---|
1981 | 18,834 |
1982 | 16,704 |
1983 | 23,466 |
1984 | 27,067 |
1985 | 26,180 |
1986 | 15,852 |
1987 | 12,314 |
1988 | 13,112 |
1989 | 5,395 |
1990 | 2,063 |
raa.latest_diagonal / 1000
1990 | |
---|---|
1981 | 18.83 |
1982 | 16.70 |
1983 | 23.47 |
1984 | 27.07 |
1985 | 26.18 |
1986 | 15.85 |
1987 | 12.31 |
1988 | 13.11 |
1989 | 5.39 |
1990 | 2.06 |
The latest diagonal also corresponds to a valuation_date
. Note that ‘valuation_date’ is a datetime that is at the terminal timestamp of the period (i.e. the last split second of the year).
raa.valuation_date
Timestamp('1990-12-31 23:59:59.999999999')
We can also tell whether our triangle:
is_cumulative
: returns True if the data across the development periods is cumulative, or False if it is incremental.is_ultimate
: returns True if the ultimate values are contained in the triangle.is_val_tri
: returns True if the development period is stated as a valuation data as opposed to an age, i.e. Schedule P style triangle (True) or the more commonly used triangle by development age (False).is_full
: returns True if the triangle has been “squared”.
print("Is triangle cumulative?", raa.is_cumulative)
print("Does triangle contain ultimate projections?", raa.is_ultimate)
print("Is this a valuation triangle?", raa.is_val_tri)
print('Has the triangle been "squared"?', raa.is_full)
Is triangle cumulative? True
Does triangle contain ultimate projections? False
Is this a valuation triangle? False
Has the triangle been "squared"? False
We can also inspect the triangle to understand its data granularity with origin_grain
and development_grain
.
print("Origin grain:", raa.origin_grain)
print("Development grain:", raa.development_grain)
Origin grain: Y
Development grain: Y
The package supports monthly (“M”), quarterly (“Q”), semester (or semi-annually), (“S”) and yearly (“Y”) grains for both origin_grain
and development_grain
.
The Triangle Structure¶
The triangle described so far is a two-dimensional (accident date by valuation date) structure that spans multiple cells of data. This is a useful structure for exploring individual triangles, but becomes more problematic when working with sets of triangles. Pandas
does not have a triangle dtype
, but if it did, working with sets of triangles would be much more convenient. To facilitate working with more than one triangle at a time the chainladder.Triangle
acts like a pandas dataframe (with an index and columns) where each cell (row x col) is an individual triangle. This structure manifests itself as a four-dimensional space. Let’s take a look at another dataset clrd
.
clrd_df = pd.read_csv(
"https://raw.githubusercontent.com/casact/chainladder-python/master/chainladder/utils/data/clrd.csv"
)
clrd_df
GRCODE | GRNAME | AccidentYear | DevelopmentYear | DevelopmentLag | IncurLoss | CumPaidLoss | BulkLoss | EarnedPremDIR | EarnedPremCeded | EarnedPremNet | Single | PostedReserve97 | LOB | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 86 | Allstate Ins Co Grp | 1988 | 1988 | 1 | 367404 | 70571 | 127737 | 400699 | 5957 | 394742 | 0 | 281872 | wkcomp |
1 | 86 | Allstate Ins Co Grp | 1988 | 1989 | 2 | 362988 | 155905 | 60173 | 400699 | 5957 | 394742 | 0 | 281872 | wkcomp |
2 | 86 | Allstate Ins Co Grp | 1988 | 1990 | 3 | 347288 | 220744 | 27763 | 400699 | 5957 | 394742 | 0 | 281872 | wkcomp |
3 | 86 | Allstate Ins Co Grp | 1988 | 1991 | 4 | 330648 | 251595 | 15280 | 400699 | 5957 | 394742 | 0 | 281872 | wkcomp |
4 | 86 | Allstate Ins Co Grp | 1988 | 1992 | 5 | 354690 | 274156 | 27689 | 400699 | 5957 | 394742 | 0 | 281872 | wkcomp |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
42840 | 44598 | College Liability Ins Co Ltd RRG | 1995 | 1996 | 2 | 343 | 249 | 82 | 397 | 0 | 397 | 1 | 630 | othliab |
42841 | 44598 | College Liability Ins Co Ltd RRG | 1995 | 1997 | 3 | 839 | 575 | 190 | 397 | 0 | 397 | 1 | 630 | othliab |
42842 | 44598 | College Liability Ins Co Ltd RRG | 1996 | 1996 | 1 | 125 | 6 | 98 | 257 | 0 | 257 | 1 | 630 | othliab |
42843 | 44598 | College Liability Ins Co Ltd RRG | 1996 | 1997 | 2 | 95 | 17 | 28 | 257 | 0 | 257 | 1 | 630 | othliab |
42844 | 44598 | College Liability Ins Co Ltd RRG | 1997 | 1997 | 1 | 83 | 4 | 77 | 256 | 0 | 256 | 1 | 630 | othliab |
42845 rows × 14 columns
Let’s load the data into the sets of triangles.
clrd = cl.Triangle(
clrd_df,
origin="AccidentYear",
development="DevelopmentYear",
columns=[
"IncurLoss",
"CumPaidLoss",
"BulkLoss",
"EarnedPremDIR",
"EarnedPremCeded",
"EarnedPremNet",
],
index=["GRNAME", "LOB"],
cumulative=True,
)
clrd
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (775, 6, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet] |
Since 4D strucures do not fit nicely on 2D screens, we see a summary view instead that describes the structure rather than the underlying data itself.
We see 5 rows of information:
Valuation: the valuation date.
Grain: the granularity of the data, O stands for origin, and D stands for development,
OYDY
represents triangles with accident year by development year.Shape: contains 4 numbers, represents the 4-D structure. This sample triangle represents a collection of 775x6 or 4,650 triangles that are themselves 10 accident years by 10 development periods.
775: the number of segments, which is the combination of
index
, that represents the data segments. In this case, it is each of theGRNAME
andLOB
unique combination.6: the number of triangles for each segment, which is also the columns
[IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet]
. They could be paid amounts, incurred amounts, reported counts, loss ratios, closure rates, excess losses, premium, etc.10: the number of accident periods.
10: the number of valuation periods.
Index: the segmentation level of the triangles.
Columns: the value types recorded in the triangles.
To summarize the set of triangles:
We have a total of 775 segments, which are at the
GRNAME
andLOB
level.Each segment contains 6 triangles, which are
IncurLoss
,CumPaidLoss
,BulkLoss
,EarnedPremDIR
,EarnedPremCeded
,EarnedPremNet
.Each triangle is 10 accident years x 10 development periods.
Using index.head()
allows us to see the first 5 segments in the set of triangles. Note that as the data is loaded, the triangle are sorted by index
, in this case, GRNAME
first, then by LOB
.
clrd.index.head()
GRNAME | LOB | |
---|---|---|
0 | Adriatic Ins Co | othliab |
1 | Adriatic Ins Co | ppauto |
2 | Aegis Grp | comauto |
3 | Aegis Grp | othliab |
4 | Aegis Grp | ppauto |
Under the hood, the data structure is a numpy.ndarray
with the equivalent shape. Like pandas, you can directly access the underlying numpy structure with the values
property. By exposing the underlying ndarray
you are free to manipulate the underlying data directly with numpy should that be an easier route to solving a problem.
print("Data structure of clrd:", type(clrd.values))
print("Sum of all data values:", np.nansum(clrd.values))
Data structure of clrd: <class 'numpy.ndarray'>
Sum of all data values: 3661713596.0
Keep in mind though, the chainladder.Triangle
has several methods and properties beyond the raw numpy representation and these are kept in sync by using the chainladder.Triangle
directly.
Pandas-Style Slicing¶
As mentioned, the 4D structure is intended to behave like a pandas DataFrame
. Like pandas, we can subset a dataframe by referencing individual columns by name.
clrd[["CumPaidLoss", "IncurLoss", "BulkLoss"]]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (775, 3, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [CumPaidLoss, IncurLoss, BulkLoss] |
We can also boolean-index the rows of the Triangle.
clrd[clrd["LOB"] == "wkcomp"]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (132, 6, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet] |
We can even use the typical loc
, iloc
functionality similar to pandas
to access subsets of data. These features can be chained together as much as you want.
clrd.loc["Allstate Ins Co Grp"].iloc[-1]["CumPaidLoss"]
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1988 | 70,571 | 155,905 | 220,744 | 251,595 | 274,156 | 287,676 | 298,499 | 304,873 | 321,808 | 325,322 |
1989 | 66,547 | 136,447 | 179,142 | 211,343 | 231,430 | 244,750 | 254,557 | 270,059 | 273,873 | |
1990 | 52,233 | 133,370 | 178,444 | 204,442 | 222,193 | 232,940 | 253,337 | 256,788 | ||
1991 | 59,315 | 128,051 | 169,793 | 196,685 | 213,165 | 234,676 | 239,195 | |||
1992 | 39,991 | 89,873 | 114,117 | 133,003 | 154,362 | 159,496 | ||||
1993 | 19,744 | 47,229 | 61,909 | 85,099 | 87,215 | |||||
1994 | 20,379 | 46,773 | 88,636 | 91,077 | ||||||
1995 | 18,756 | 84,712 | 87,311 | |||||||
1996 | 42,609 | 44,916 | ||||||||
1997 | 691 |
Pandas-Style Arithmetic¶
With complete flexibility in the ability to slice subsets of triangles, we can use basic arithmetic to derive new triangles, which is commonly used as diagnostics to explore trends.
clrd["CaseIncurLoss"] = clrd["IncurLoss"] - clrd["BulkLoss"]
clrd["PaidToInc"] = clrd["CumPaidLoss"] / clrd["CaseIncurLoss"]
clrd[["CaseIncurLoss", "PaidToInc"]]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (775, 2, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [CaseIncurLoss, PaidToInc] |
We can also aggregating the values across all triangles into one triangle.
clrd["CumPaidLoss"].sum()
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1988 | 3,577,780 | 7,059,966 | 8,826,151 | 9,862,687 | 10,474,698 | 10,814,576 | 10,994,014 | 11,091,363 | 11,171,590 | 11,203,949 |
1989 | 4,090,680 | 7,964,702 | 9,937,520 | 11,098,588 | 11,766,488 | 12,118,790 | 12,311,629 | 12,434,826 | 12,492,899 | |
1990 | 4,578,442 | 8,808,486 | 10,985,347 | 12,229,001 | 12,878,545 | 13,238,667 | 13,452,993 | 13,559,557 | ||
1991 | 4,648,756 | 8,961,755 | 11,154,244 | 12,409,592 | 13,092,037 | 13,447,481 | 13,642,414 | |||
1992 | 5,139,142 | 9,757,699 | 12,027,983 | 13,289,485 | 13,992,821 | 14,347,271 | ||||
1993 | 5,653,379 | 10,599,423 | 12,953,812 | 14,292,516 | 15,005,138 | |||||
1994 | 6,246,447 | 11,394,960 | 13,845,764 | 15,249,326 | ||||||
1995 | 6,473,843 | 11,612,151 | 14,010,098 | |||||||
1996 | 6,591,599 | 11,473,912 | ||||||||
1997 | 6,451,896 |
We can also construct a paid loss ratio triangle against EarnedPremNet
.
clrd["CumPaidLoss"].sum() / clrd["EarnedPremNet"].sum()
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1988 | 0.2581 | 0.5093 | 0.6368 | 0.7115 | 0.7557 | 0.7802 | 0.7932 | 0.8002 | 0.8060 | 0.8083 |
1989 | 0.2686 | 0.5230 | 0.6526 | 0.7288 | 0.7727 | 0.7958 | 0.8085 | 0.8166 | 0.8204 | |
1990 | 0.2728 | 0.5249 | 0.6546 | 0.7287 | 0.7674 | 0.7888 | 0.8016 | 0.8080 | ||
1991 | 0.2540 | 0.4896 | 0.6093 | 0.6779 | 0.7152 | 0.7346 | 0.7453 | |||
1992 | 0.2595 | 0.4927 | 0.6074 | 0.6711 | 0.7066 | 0.7245 | ||||
1993 | 0.2645 | 0.4959 | 0.6061 | 0.6687 | 0.7021 | |||||
1994 | 0.2709 | 0.4942 | 0.6005 | 0.6614 | ||||||
1995 | 0.2651 | 0.4755 | 0.5737 | |||||||
1996 | 0.2635 | 0.4586 | ||||||||
1997 | 0.2552 |
Aggregating all segments together is interesting, but it is often more useful to aggregate across segments using groupby
. For example, we may want to group the triangles by line of business and get a sum across all companies for each industry.
clrd.groupby("LOB").sum()
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (6, 8, 10, 10) |
Index: | [LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet, CaseIncurLoss, PaidToInc] |
The shape is (6, 8, 10, 10) because now we have 6 LOBs with 8 triangles for each LOB. We can also note that index
is now on [LOB]
only.
np.unique(clrd["LOB"])
array(['comauto', 'medmal', 'othliab', 'ppauto', 'prodliab', 'wkcomp'],
dtype=object)
The aggregation functions, e.g. sum
, mean
, std
, min
, max
, etc. don’t have to just apply to the index
axis. You can apply them to any of the four axes in the triangle object, which are segments
(axis 0
, or the index axis), columns
(axis 1
, the various financial fields), origin
(axis 2
, across triangle rows), and development
period (axis 3
, across triangle columns). You can also use either the axis name or number. Let’s try to sum all of the segments ([GRNAME, LOB]
) and columns ([IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet]
) using axis name and number, respectively.
clrd.sum(axis="index").sum(axis="segments")
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (1, 8, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet, CaseIncurLoss, PaidToInc] |
clrd.sum(axis=0).sum(axis=1)
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
1988 | 56,387,734 | 59,928,520 | 61,653,458 | 62,644,631 | 63,182,710 | 63,438,080 | 63,440,904 | 63,452,111 | 63,522,981 | 63,518,183 |
1989 | 62,840,448 | 66,705,570 | 68,666,928 | 69,702,283 | 70,188,013 | 70,355,679 | 70,389,857 | 70,453,158 | 70,483,269 | |
1990 | 70,064,967 | 74,084,388 | 75,879,276 | 76,812,990 | 77,179,572 | 77,240,321 | 77,283,937 | 77,345,588 | ||
1991 | 74,611,611 | 78,513,121 | 80,235,908 | 80,967,061 | 81,178,876 | 81,185,484 | 81,278,636 | |||
1992 | 81,213,791 | 85,089,370 | 86,443,882 | 86,783,107 | 86,908,610 | 87,086,637 | ||||
1993 | 87,896,227 | 91,685,456 | 93,018,485 | 93,167,810 | 93,473,079 | |||||
1994 | 94,593,702 | 98,130,718 | 99,071,781 | 99,809,122 | ||||||
1995 | 97,722,814 | 101,192,332 | 102,056,680 | |||||||
1996 | 98,497,932 | 100,917,690 | ||||||||
1997 | 96,832,221 |
Accessor Methods¶
Pandas
has special “accessor” methods for str
and dt
. These allow for the manipulation of data within each cell of data:
# splits lastname from first name by a comma-delimiter
df['Last_First'].str.split(',')
# pulls the year out of each date in a dataframe column
df['Accident Date'].dt.year
chainladder
also has special “accessor” methods to help us manipulate the origin
, development
and valuation
vectors of a triangle.
We may want to extract only the latest accident period for every triangle.
clrd[clrd.origin == clrd.origin.max()]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (775, 8, 1, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet, CaseIncurLoss, PaidToInc] |
Note that this triangle has only 1 row; however, all of the columns would exist, but only the youngest age would have values.
We may want to extract particular diagonals from our triangles using its valuation
vector.
clrd[(clrd.valuation >= "1994") & (clrd.valuation < "1995")]["CumPaidLoss"].sum()
12 | 24 | 36 | 48 | 60 | 72 | 84 | |
---|---|---|---|---|---|---|---|
1988 | 10,994,014 | ||||||
1989 | 12,118,790 | ||||||
1990 | 12,878,545 | ||||||
1991 | 12,409,592 | ||||||
1992 | 12,027,983 | ||||||
1993 | 10,599,423 | ||||||
1994 | 6,246,447 |
We may even want to slice particular development periods to explore aspects of our data by development age. For example, we can look at the development factors between ages 24 and 36.
clrd[(clrd.development > 12) & (clrd.development <= 36)]["CumPaidLoss"].sum().link_ratio
24-36 | |
---|---|
1988 | 1.2502 |
1989 | 1.2477 |
1990 | 1.2471 |
1991 | 1.2446 |
1992 | 1.2327 |
1993 | 1.2221 |
1994 | 1.2151 |
1995 | 1.2065 |
1996 | |
1997 |
Moving Back to Pandas¶
When the shape of a Triangle
object can be expressed as a 2D structure (i.e. two of its four axes have a length of 1) or less, you can use the to_frame
method to convert your data into a pandas.DataFrame
. Let’s pick only one financial field, CumPaidLoss
and only the latest diagonal, with latest_diagonal
. We are now left with LOBs and origin period as our 2 axes.
clrd.groupby("LOB").sum().latest_diagonal["CumPaidLoss"]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (6, 1, 10, 1) |
Index: | [LOB] |
Columns: | [CumPaidLoss] |
clrd.groupby("LOB").sum().latest_diagonal["CumPaidLoss"].to_frame(
origin_as_datetime=True
).astype(int)
origin | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 |
---|---|---|---|---|---|---|---|---|---|---|
LOB | ||||||||||
comauto | 626097 | 674441 | 718396 | 711762 | 731033 | 762039 | 768095 | 675166 | 510191 | 272342 |
medmal | 217239 | 222707 | 235717 | 275923 | 267007 | 276235 | 252449 | 209222 | 107474 | 20361 |
othliab | 317889 | 350684 | 361103 | 426085 | 389250 | 434995 | 402244 | 294332 | 191258 | 54130 |
ppauto | 8690036 | 9823747 | 10728411 | 10713621 | 11555121 | 12249826 | 12600432 | 11807279 | 9900842 | 5754249 |
prodliab | 110973 | 112614 | 121255 | 100276 | 76059 | 94462 | 111264 | 62018 | 28107 | 10682 |
wkcomp | 1241715 | 1308706 | 1394675 | 1414747 | 1328801 | 1187581 | 1114842 | 962081 | 736040 | 340132 |
Note that we added origin_as_datetime=True
inside of to_frame(...)
as the package is under-going a deprecation cycle. You can also execute the same code without the origin_as_datetime=...
, but you will get a warning.
clrd.groupby("LOB").sum().latest_diagonal["CumPaidLoss"].to_frame().astype(int)
origin | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 |
---|---|---|---|---|---|---|---|---|---|---|
LOB | ||||||||||
comauto | 626097 | 674441 | 718396 | 711762 | 731033 | 762039 | 768095 | 675166 | 510191 | 272342 |
medmal | 217239 | 222707 | 235717 | 275923 | 267007 | 276235 | 252449 | 209222 | 107474 | 20361 |
othliab | 317889 | 350684 | 361103 | 426085 | 389250 | 434995 | 402244 | 294332 | 191258 | 54130 |
ppauto | 8690036 | 9823747 | 10728411 | 10713621 | 11555121 | 12249826 | 12600432 | 11807279 | 9900842 | 5754249 |
prodliab | 110973 | 112614 | 121255 | 100276 | 76059 | 94462 | 111264 | 62018 | 28107 | 10682 |
wkcomp | 1241715 | 1308706 | 1394675 | 1414747 | 1328801 | 1187581 | 1114842 | 962081 | 736040 | 340132 |
We can also aggregate process away 3 dimensions, then use to_frame
.
clrd[clrd.origin == "1990"].groupby("LOB").sum().latest_diagonal[
"CumPaidLoss"
].to_frame(origin_as_datetime=True).astype(int)
LOB
comauto 718396
medmal 235717
othliab 361103
ppauto 10728411
prodliab 121255
wkcomp 1394675
dtype: int64
Exercises¶
Use the clrd
dataset for all of the exercises.
How do we create a new column named “NetPaidLossRatio” in the triangle using the existing columns?
clrd["NetPaidLossRatio"] = clrd["CumPaidLoss"] / clrd["EarnedPremNet"]
What is the highest paid loss ratio for across all segments for origin 1997 at age 12?
clrd[clrd.origin == "1997"][clrd.development == 12]["NetPaidLossRatio"].max()
4.769123134328358
How do we subset the overall triangle to just include “Alaska Nat Ins Co”?
clrd[clrd["GRNAME"] == "Alaska Nat Ins Co"]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (4, 9, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet, CaseIncurLoss, PaidToInc, NetPaidLossRatio] |
How do we create a triangle subset that includes all triangles for companies with names starting with the letter “B”?
clrd[clrd["GRNAME"].str[0] == "B"]
Triangle Summary | |
---|---|
Valuation: | 1997-12 |
Grain: | OYDY |
Shape: | (31, 9, 10, 10) |
Index: | [GRNAME, LOB] |
Columns: | [IncurLoss, CumPaidLoss, BulkLoss, EarnedPremDIR, EarnedPremCeded, EarnedPremNet, CaseIncurLoss, PaidToInc, NetPaidLossRatio] |
Which are the top 5 companies by net premium share for in 1990?
clrd.latest_diagonal.groupby("GRNAME").sum()[clrd.origin == "1990"][
"EarnedPremNet"
].to_frame(origin_as_datetime=True).sort_values(ascending=False).iloc[0:5]
GRNAME
State Farm Mut Grp 10532675.0
United Services Automobile Asn Grp 1378791.0
Federal Ins Co Grp 477150.0
New Jersey Manufacturers Grp 383870.0
FL Farm Bureau Grp 342036.0
dtype: float64
Initializing a Triangle With Your Own Data¶
The chainladder.Triangle
class is designed to ingest pandas.DataFrame
objects. However, you do not need to worry about shaping the dataframe into triangle format yourself. This happens at the time you ingest the data.
Let’s look at the initialization signature and its docstring.
cl.Triangle?
Let’s use a new dataset prism
to construct our triangles.
prism_df = pd.read_csv(
"https://raw.githubusercontent.com/casact/chainladder-python/master/chainladder/utils/data/prism.csv"
)
prism_df.head()
ClaimNo | AccidentDate | ReportDate | Line | Type | ClaimLiability | Limit | Deductible | TotalPayment | PaymentDate | CloseDate | Status | reportedCount | closedPaidCount | closedUnPaidCount | openCount | Paid | Outstanding | Incurred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2008-01-22 | 4/19/2010 | Home | Dwelling | False | 300000.0 | 20000 | 0.00000 | 2010-10-08 | 10/8/2010 | CLOSED | 1 | 0 | 1 | 0 | 0.00000 | 0 | 0.00000 |
1 | 2 | 2008-01-02 | 4/20/2010 | Home | Dwelling | False | 200000.0 | 20000 | 0.00000 | 2010-11-30 | 11/30/2010 | CLOSED | 1 | 0 | 1 | 0 | 0.00000 | 0 | 0.00000 |
2 | 3 | 2008-01-01 | 9/23/2009 | Home | Dwelling | True | 200000.0 | 20000 | 115744.77370 | 2010-02-17 | 2/17/2010 | CLOSED | 1 | 1 | 0 | 0 | 115744.77370 | 0 | 115744.77370 |
3 | 4 | 2008-01-02 | 7/25/2009 | Home | Dwelling | True | 200000.0 | 20000 | 63678.87713 | 2009-11-18 | 11/18/2009 | CLOSED | 1 | 1 | 0 | 0 | 63678.87713 | 0 | 63678.87713 |
4 | 5 | 2008-01-16 | 12/7/2009 | Home | Dwelling | True | 200000.0 | 20000 | 112175.55590 | 2010-04-30 | 4/30/2010 | CLOSED | 1 | 1 | 0 | 0 | 112175.55590 | 0 | 112175.55590 |
prism_df.dtypes
ClaimNo int64
AccidentDate object
ReportDate object
Line object
Type object
ClaimLiability bool
Limit float64
Deductible int64
TotalPayment float64
PaymentDate object
CloseDate object
Status object
reportedCount int64
closedPaidCount int64
closedUnPaidCount int64
openCount int64
Paid float64
Outstanding int64
Incurred float64
dtype: object
We must specify the origin
, development
, columns
, and cumulative
to create a triangle object. By limiting our columns to one measure and not specifying an index, we can create a single triangle. For example, if we are only interested in the paid triangle. Because the data we have is transactional data, the cumulative
variable should be set to False
.
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
development="PaymentDate",
columns="Paid",
cumulative=False,
)
prism
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2008-01 | 46,915 | 19,899 | 57,216 | 89,783 | 18,302 | 95,054 | 10,332 | 91,772 | ... | ||||||||||||
2008-02 | 28,749 | 22,109 | 79,033 | 63,455 | 59,993 | 64,683 | 68,502 | 33,695 | 71,670 | ... | |||||||||||
2008-03 | 48,806 | 27,949 | 90,413 | 54,557 | 83,507 | 12,591 | 72,035 | 70,353 | 35,223 | ... | |||||||||||
2008-04 | 30,758 | 17,763 | 70,872 | 30,233 | 39,494 | 66,729 | 122,100 | 20,998 | 38,218 | ... | |||||||||||
2008-05 | 38,672 | 86,974 | 20,483 | 58,400 | 112,015 | 31,354 | 22,457 | 53,778 | 93,303 | ... | |||||||||||
2008-06 | 56,789 | 73,351 | 97,840 | 64,816 | 61,083 | 41,685 | 87,172 | 61,418 | 63,097 | ... | |||||||||||
2008-07 | 27,867 | 45,804 | 61,495 | 73,279 | 71,591 | 111,807 | 80,249 | 40,632 | 32,434 | ... | |||||||||||
2008-08 | 4,832 | 23,831 | 52,511 | 62,649 | 45,955 | 133,133 | 81,733 | 39,709 | 112,115 | 21,367 | ... | ||||||||||
2008-09 | 43,464 | 86,157 | 52,664 | 89,928 | 88,738 | 55,617 | 26,599 | 69,522 | 46,788 | ... | |||||||||||
2008-10 | 12,488 | 21,939 | 53,388 | 52,415 | 92,086 | 45,781 | 72,242 | 83,359 | 47,594 | ... | |||||||||||
2008-11 | 45,473 | 9,416 | 78,967 | 84,826 | 39,549 | 41,011 | 74,000 | 33,257 | 35,802 | ... | |||||||||||
2008-12 | 3,640 | 9,905 | 54,792 | 87,057 | 70,686 | 54,775 | 31,412 | 44,057 | 59,448 | 31,643 | ... | ||||||||||
2009-01 | 14,021 | 45,350 | 51,208 | 35,520 | 81,655 | 54,275 | 41,538 | 74,129 | 47,962 | ... | |||||||||||
2009-02 | 10,305 | 35,026 | 37,289 | 58,773 | 67,579 | 57,589 | 115,083 | 57,142 | 65,315 | 55,019 | ... | ||||||||||
2009-03 | 48,360 | 40,502 | 74,342 | 64,538 | 49,778 | 85,591 | 82,582 | 56,449 | 88,307 | ... | |||||||||||
2009-04 | 40,943 | 47,517 | 64,024 | 27,573 | 62,634 | 54,051 | 63,305 | 61,339 | 70,406 | ... | |||||||||||
2009-05 | 16,944 | 74,478 | 63,856 | 59,266 | 79,707 | 63,857 | 59,326 | 88,817 | 50,656 | ... | |||||||||||
2009-06 | 9,655 | 43,720 | 12,805 | 79,404 | 46,219 | 46,868 | 36,234 | 35,654 | 24,676 | 26,641 | ... | ||||||||||
2009-07 | 14,828 | 48,605 | 90,527 | 54,508 | 57,881 | 64,905 | 16,717 | 46,880 | 89,721 | ... | |||||||||||
2009-08 | 42,061 | 32,247 | 64,174 | 63,443 | 65,428 | 95,432 | 91,809 | 131,904 | 67,284 | ... | |||||||||||
2009-09 | 21,000 | 27,607 | 34,679 | 37,523 | 56,305 | 42,851 | 72,404 | 54,366 | 67,543 | 71,032 | ... | ||||||||||
2009-10 | 14,000 | 62,040 | 45,134 | 97,016 | 54,356 | 20,848 | 63,521 | 78,494 | 67,441 | 22,107 | ... | ||||||||||
2009-11 | 22,027 | 64,189 | 20,836 | 33,303 | 50,594 | 79,852 | 54,870 | 111,592 | 70,473 | ... | |||||||||||
2009-12 | 38,594 | 17,902 | 100,470 | 43,866 | 102,051 | 56,901 | 33,876 | 40,416 | 54,734 | ... | |||||||||||
2010-01 | 15,192 | 53,338 | 57,394 | 56,985 | 62,175 | 84,624 | 84,959 | 102,734 | 26,495 | ... | |||||||||||
2010-02 | 7,000 | 31,464 | 32,942 | 38,108 | 28,707 | 100,091 | 97,795 | 98,314 | 53,259 | 96,477 | ... | ||||||||||
2010-03 | 36,937 | 64,551 | 61,774 | 39,580 | 81,253 | 35,751 | 87,788 | 41,076 | 117,835 | ... | |||||||||||
2010-04 | 21,026 | 32,422 | 46,661 | 103,442 | 89,860 | 96,976 | 51,116 | 89,352 | 50,595 | 13,981 | ... | ||||||||||
2010-05 | 8,668 | 8,920 | 116,376 | 61,586 | 148,647 | 14,288 | 46,840 | 51,205 | 82,714 | 4,240 | ... | ||||||||||
2010-06 | 12,578 | 92,156 | 44,495 | 112,868 | 79,732 | 73,743 | 61,814 | 73,713 | 23,724 | ... | |||||||||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2015-07 | 5,872 | 61,431 | 113,522 | 96,030 | 133,267 | 130,305 | 64,905 | 58,480 | 94,985 | 72,184 | ... | ||||||||||
2015-08 | 12,276 | 73,666 | 69,772 | 156,546 | 96,829 | 122,893 | 77,525 | 120,597 | 42,213 | 81,603 | ... | ||||||||||
2015-09 | 29,402 | 45,522 | 76,968 | 146,840 | 171,674 | 109,429 | 86,091 | 98,514 | 83,465 | 61,289 | ... | ||||||||||
2015-10 | 14,000 | 18,824 | 64,809 | 86,112 | 33,952 | 94,798 | 41,473 | 114,279 | 95,470 | 95,322 | ... | ||||||||||
2015-11 | 24,866 | 74,507 | 52,944 | 109,360 | 98,136 | 160,381 | 46,511 | 206,774 | 128,625 | ... | |||||||||||
2015-12 | 14,000 | 34,498 | 85,505 | 113,846 | 118,239 | 121,277 | 179,033 | 131,330 | 130,357 | 89,312 | ... | ||||||||||
2016-01 | 3,214 | 16,521 | 48,605 | 63,442 | 64,330 | 156,536 | 70,536 | 90,186 | 88,647 | 87,278 | ... | ||||||||||
2016-02 | 13,892 | 20,722 | 112,166 | 154,319 | 93,667 | 117,578 | 114,468 | 77,207 | 79,020 | 85,925 | ... | ||||||||||
2016-03 | 18,354 | 48,495 | 70,675 | 115,886 | 83,612 | 45,276 | 123,736 | 114,339 | 79,022 | 96,179 | ... | ||||||||||
2016-04 | 14,781 | 35,741 | 51,818 | 124,195 | 76,220 | 168,821 | 117,505 | 82,978 | 99,148 | 112,664 | ... | ||||||||||
2016-05 | 32,921 | 80,574 | 128,677 | 98,491 | 138,236 | 110,125 | 110,887 | 150,281 | 74,849 | ... | |||||||||||
2016-06 | 17,959 | 9,031 | 35,721 | 163,644 | 172,139 | 157,653 | 154,168 | 120,193 | 100,214 | 62,572 | ... | ||||||||||
2016-07 | 36,454 | 24,783 | 105,234 | 116,616 | 64,114 | 118,426 | 107,283 | 101,315 | 136,164 | 95,888 | ... | ||||||||||
2016-08 | 45,280 | 14,224 | 93,541 | 147,758 | 88,370 | 195,297 | 117,494 | 57,656 | 132,907 | 100,460 | ... | ||||||||||
2016-09 | 13,544 | 56,468 | 84,514 | 106,896 | 127,088 | 89,314 | 132,691 | 153,691 | 62,591 | 133,208 | ... | ||||||||||
2016-10 | 1,766 | 61,196 | 80,437 | 123,346 | 82,947 | 158,137 | 168,589 | 110,019 | 86,504 | 162,549 | ... | ||||||||||
2016-11 | 55,837 | 111,442 | 110,741 | 111,772 | 44,847 | 164,147 | 180,126 | 90,889 | 71,973 | ... | |||||||||||
2016-12 | 52,806 | 55,386 | 116,175 | 107,611 | 109,759 | 74,635 | 145,938 | 100,703 | 114,897 | ... | |||||||||||
2017-01 | 8,338 | 26,000 | 121,221 | 104,138 | 113,300 | 86,086 | 139,369 | 127,013 | 66,155 | 111,713 | ... | ||||||||||
2017-02 | 50,237 | 101,651 | 103,479 | 94,798 | 94,285 | 160,239 | 141,802 | 131,585 | 94,257 | ... | |||||||||||
2017-03 | 4,476 | 20,775 | 74,392 | 72,250 | 143,323 | 56,307 | 210,407 | 117,054 | 101,546 | 93,077 | ... | ||||||||||
2017-04 | 30,751 | 126,808 | 154,839 | 157,090 | 72,106 | 102,587 | 91,454 | 142,689 | ... | ||||||||||||
2017-05 | 3,022 | 36,811 | 54,334 | 80,437 | 81,315 | 160,838 | 180,652 | 88,441 | ... | ||||||||||||
2017-06 | 31,858 | 37,911 | 81,229 | 121,619 | 85,185 | 110,103 | ... | ||||||||||||||
2017-07 | 28,827 | 30,987 | 126,230 | 72,826 | 80,075 | 119,390 | ... | ||||||||||||||
2017-08 | 14,000 | 105,952 | 81,991 | 174,870 | ... | ||||||||||||||||
2017-09 | 18,589 | 33,317 | 86,057 | 152,144 | ... | ||||||||||||||||
2017-10 | 35,037 | 104,444 | ... | ||||||||||||||||||
2017-11 | 4,088 | 10,599 | ... | ||||||||||||||||||
2017-12 | 10,748 | ... |
Note that the lowest (most-detailed) grain supported is the monthly grain, so the triangle above is aggregated to the OMDM level.
prism.origin_grain
'M'
prism.development_grain
'M'
If we want to include more columns or indices we can certainly do so. Note that as we do this, we move into the 4D arena changing the display of the overall object.
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
development="PaymentDate",
columns=["Paid", "Incurred"],
cumulative=False,
)
prism
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OMDM |
Shape: | (1, 2, 120, 120) |
Index: | [Total] |
Columns: | [Paid, Incurred] |
Pandas
has wonderful datetime inference functionality that the Triangle
heavily uses to infer origin and development granularity. Even still, there are occassions where date format inferences can fail. It is often better to explicitly tell the triangle the date format, and is usually good pratice to explicitly state the date format instead.
prism_df.head()
ClaimNo | AccidentDate | ReportDate | Line | Type | ClaimLiability | Limit | Deductible | TotalPayment | PaymentDate | CloseDate | Status | reportedCount | closedPaidCount | closedUnPaidCount | openCount | Paid | Outstanding | Incurred | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2008-01-22 | 4/19/2010 | Home | Dwelling | False | 300000.0 | 20000 | 0.00000 | 2010-10-08 | 10/8/2010 | CLOSED | 1 | 0 | 1 | 0 | 0.00000 | 0 | 0.00000 |
1 | 2 | 2008-01-02 | 4/20/2010 | Home | Dwelling | False | 200000.0 | 20000 | 0.00000 | 2010-11-30 | 11/30/2010 | CLOSED | 1 | 0 | 1 | 0 | 0.00000 | 0 | 0.00000 |
2 | 3 | 2008-01-01 | 9/23/2009 | Home | Dwelling | True | 200000.0 | 20000 | 115744.77370 | 2010-02-17 | 2/17/2010 | CLOSED | 1 | 1 | 0 | 0 | 115744.77370 | 0 | 115744.77370 |
3 | 4 | 2008-01-02 | 7/25/2009 | Home | Dwelling | True | 200000.0 | 20000 | 63678.87713 | 2009-11-18 | 11/18/2009 | CLOSED | 1 | 1 | 0 | 0 | 63678.87713 | 0 | 63678.87713 |
4 | 5 | 2008-01-16 | 12/7/2009 | Home | Dwelling | True | 200000.0 | 20000 | 112175.55590 | 2010-04-30 | 4/30/2010 | CLOSED | 1 | 1 | 0 | 0 | 112175.55590 | 0 | 112175.55590 |
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
origin_format="%Y-%m-%d",
development="PaymentDate",
development_format="%Y-%m-%d",
columns=["Paid", "Incurred"],
cumulative=False,
)
prism
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OMDM |
Shape: | (1, 2, 120, 120) |
Index: | [Total] |
Columns: | [Paid, Incurred] |
Up until now, we’ve been playing with symmetric triangles (i.e. orgin
and development
periods have the same grain). However, nothing precludes us from having a different grain. Often times in practice the development
axis is more granular than the origin
axis. All the functionality available to symmetric triangles works equally well for asymmetric triangles.
prism_df["AccYr"] = prism_df["AccidentDate"].str[:4]
prism = cl.Triangle(
data=prism_df,
origin="AccYr",
origin_format="%Y",
development="PaymentDate",
development_format="%Y-%m-%d",
columns=["Paid", "Incurred"],
cumulative=False,
)
prism["Paid"]
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2008 | 75,664 | 90,814 | 194,956 | 300,085 | 347,487 | 400,011 | 356,795 | 598,532 | ... | 7,000 | |||||||||||
2009 | 24,327 | 80,376 | 136,857 | 175,737 | 297,690 | 358,624 | 325,462 | 529,832 | 540,217 | ... | |||||||||||
2010 | 22,192 | 84,802 | 148,299 | 200,733 | 208,237 | 456,692 | 519,691 | 604,946 | 484,188 | ... | |||||||||||
2011 | 24,934 | 60,404 | 107,198 | 233,346 | 268,904 | 401,595 | 530,490 | 501,836 | 513,133 | ... | |||||||||||
2012 | 18,794 | 98,320 | 165,689 | 296,865 | 335,643 | 320,954 | 529,733 | 592,985 | 686,689 | ... | |||||||||||
2013 | 70,959 | 99,628 | 238,991 | 180,138 | 302,213 | 477,224 | 585,963 | 648,734 | 637,203 | ... | |||||||||||
2014 | 18,194 | 32,772 | 124,801 | 276,336 | 344,635 | 425,875 | 449,242 | 541,203 | 587,789 | 819,083 | ... | ||||||||||
2015 | 31,221 | 86,418 | 242,766 | 276,598 | 418,870 | 575,634 | 620,098 | 858,771 | 787,203 | ... | |||||||||||
2016 | 3,214 | 30,412 | 87,680 | 238,884 | 325,065 | 468,785 | 521,981 | 560,611 | 853,548 | 976,906 | ... | ||||||||||
2017 | 8,338 | 26,000 | 175,935 | 226,565 | 324,943 | 416,752 | 646,836 | 649,985 | 811,832 | 957,490 | ... |
While exposure triangles make sense for auditable lines such as workers’ compensation lines, most other lines of business’ exposures can be expressed as a 1D array (along origin period) as exposures do not develop over time. chainladder
arithmetic requires that operations happen between a triangle and either an int
, float
, or another Triangle
. To create a 1D exposure array, simply omit the development
argument at initialization.
The prism
data does not consist of exposure data, but we can contrive one. Let’s assume that the premium is thrice the incurred amount.
prism_df["Premium"] = 3 * prism_df["Incurred"]
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
origin_format="%Y-%m-%d",
columns="Premium",
cumulative=False,
)
prism
2017-12 | |
---|---|
2008-01 | 41,872,294 |
2008-02 | 43,542,684 |
2008-03 | 35,920,802 |
2008-04 | 30,521,592 |
2008-05 | 46,807,611 |
2008-06 | 35,926,236 |
2008-07 | 33,305,612 |
2008-08 | 35,667,952 |
2008-09 | 36,773,174 |
2008-10 | 36,858,772 |
2008-11 | 41,939,041 |
2008-12 | 34,716,883 |
2009-01 | 40,435,087 |
2009-02 | 51,803,670 |
2009-03 | 38,273,957 |
2009-04 | 44,045,041 |
2009-05 | 38,573,516 |
2009-06 | 34,674,998 |
2009-07 | 39,372,633 |
2009-08 | 41,936,689 |
2009-09 | 39,120,076 |
2009-10 | 33,485,416 |
2009-11 | 35,884,763 |
2009-12 | 35,640,359 |
2010-01 | 39,187,508 |
2010-02 | 36,408,113 |
2010-03 | 46,100,329 |
2010-04 | 39,311,907 |
2010-05 | 38,617,436 |
2010-06 | 38,204,654 |
... | ... |
2015-07 | 18,075,734 |
2015-08 | 12,204,463 |
2015-09 | 11,209,737 |
2015-10 | 7,647,748 |
2015-11 | 6,591,418 |
2015-12 | 7,948,603 |
2016-01 | 5,502,819 |
2016-02 | 5,677,216 |
2016-03 | 4,541,502 |
2016-04 | 4,938,965 |
2016-05 | 4,522,476 |
2016-06 | 4,664,779 |
2016-07 | 5,134,766 |
2016-08 | 4,554,252 |
2016-09 | 4,406,520 |
2016-10 | 4,278,755 |
2016-11 | 3,955,199 |
2016-12 | 3,586,924 |
2017-01 | 3,446,326 |
2017-02 | 3,095,700 |
2017-03 | 2,680,826 |
2017-04 | 2,634,972 |
2017-05 | 2,057,550 |
2017-06 | 1,403,713 |
2017-07 | 1,375,008 |
2017-08 | 1,130,442 |
2017-09 | 870,320 |
2017-10 | 418,445 |
2017-11 | 44,062 |
2017-12 | 32,244 |
Let’s seperate our data by segments using index
:
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
origin_format="%Y-%m-%d",
development="PaymentDate",
development_format="%Y-%m-%d",
columns=["Paid", "Incurred"],
index="Line",
cumulative=False,
)
prism
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OMDM |
Shape: | (2, 2, 120, 120) |
Index: | [Line] |
Columns: | [Paid, Incurred] |
We can futher index
by coverages, or sublines:
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
origin_format="%Y-%m-%d",
development="PaymentDate",
development_format="%Y-%m-%d",
columns=["Paid", "Incurred"],
index=["Line", "Type"],
cumulative=False,
)
prism
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OMDM |
Shape: | (2, 2, 120, 120) |
Index: | [Line, Type] |
Columns: | [Paid, Incurred] |
Triangle Methods not Available in Pandas¶
Up until now, we’ve kept pretty close to the pandas API for triangle manipulation. However, there are data transformations commonly applied to triangles that don’t have a nice pandas
analogy.
For example, we often want to convert a triangle from an incremental view into a cumulative view and vice versa. This can be accomplished with the incr_to_cum
and cum_to_incr
methods.
prism["Paid"].sum()
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2008-01 | 46,915 | 19,899 | 57,216 | 89,783 | 18,302 | 95,054 | 10,332 | 91,772 | ... | ||||||||||||
2008-02 | 28,749 | 22,109 | 79,033 | 63,455 | 59,993 | 64,683 | 68,502 | 33,695 | 71,670 | ... | |||||||||||
2008-03 | 48,806 | 27,949 | 90,413 | 54,557 | 83,507 | 12,591 | 72,035 | 70,353 | 35,223 | ... | |||||||||||
2008-04 | 30,758 | 17,763 | 70,872 | 30,233 | 39,494 | 66,729 | 122,100 | 20,998 | 38,218 | ... | |||||||||||
2008-05 | 38,672 | 86,974 | 20,483 | 58,400 | 112,015 | 31,354 | 22,457 | 53,778 | 93,303 | ... | |||||||||||
2008-06 | 56,789 | 73,351 | 97,840 | 64,816 | 61,083 | 41,685 | 87,172 | 61,418 | 63,097 | ... | |||||||||||
2008-07 | 27,867 | 45,804 | 61,495 | 73,279 | 71,591 | 111,807 | 80,249 | 40,632 | 32,434 | ... | |||||||||||
2008-08 | 4,832 | 23,831 | 52,511 | 62,649 | 45,955 | 133,133 | 81,733 | 39,709 | 112,115 | 21,367 | ... | ||||||||||
2008-09 | 43,464 | 86,157 | 52,664 | 89,928 | 88,738 | 55,617 | 26,599 | 69,522 | 46,788 | ... | |||||||||||
2008-10 | 12,488 | 21,939 | 53,388 | 52,415 | 92,086 | 45,781 | 72,242 | 83,359 | 47,594 | ... | |||||||||||
2008-11 | 45,473 | 9,416 | 78,967 | 84,826 | 39,549 | 41,011 | 74,000 | 33,257 | 35,802 | ... | |||||||||||
2008-12 | 3,640 | 9,905 | 54,792 | 87,057 | 70,686 | 54,775 | 31,412 | 44,057 | 59,448 | 31,643 | ... | ||||||||||
2009-01 | 14,021 | 45,350 | 51,208 | 35,520 | 81,655 | 54,275 | 41,538 | 74,129 | 47,962 | ... | |||||||||||
2009-02 | 10,305 | 35,026 | 37,289 | 58,773 | 67,579 | 57,589 | 115,083 | 57,142 | 65,315 | 55,019 | ... | ||||||||||
2009-03 | 48,360 | 40,502 | 74,342 | 64,538 | 49,778 | 85,591 | 82,582 | 56,449 | 88,307 | ... | |||||||||||
2009-04 | 40,943 | 47,517 | 64,024 | 27,573 | 62,634 | 54,051 | 63,305 | 61,339 | 70,406 | ... | |||||||||||
2009-05 | 16,944 | 74,478 | 63,856 | 59,266 | 79,707 | 63,857 | 59,326 | 88,817 | 50,656 | ... | |||||||||||
2009-06 | 9,655 | 43,720 | 12,805 | 79,404 | 46,219 | 46,868 | 36,234 | 35,654 | 24,676 | 26,641 | ... | ||||||||||
2009-07 | 14,828 | 48,605 | 90,527 | 54,508 | 57,881 | 64,905 | 16,717 | 46,880 | 89,721 | ... | |||||||||||
2009-08 | 42,061 | 32,247 | 64,174 | 63,443 | 65,428 | 95,432 | 91,809 | 131,904 | 67,284 | ... | |||||||||||
2009-09 | 21,000 | 27,607 | 34,679 | 37,523 | 56,305 | 42,851 | 72,404 | 54,366 | 67,543 | 71,032 | ... | ||||||||||
2009-10 | 14,000 | 62,040 | 45,134 | 97,016 | 54,356 | 20,848 | 63,521 | 78,494 | 67,441 | 22,107 | ... | ||||||||||
2009-11 | 22,027 | 64,189 | 20,836 | 33,303 | 50,594 | 79,852 | 54,870 | 111,592 | 70,473 | ... | |||||||||||
2009-12 | 38,594 | 17,902 | 100,470 | 43,866 | 102,051 | 56,901 | 33,876 | 40,416 | 54,734 | ... | |||||||||||
2010-01 | 15,192 | 53,338 | 57,394 | 56,985 | 62,175 | 84,624 | 84,959 | 102,734 | 26,495 | ... | |||||||||||
2010-02 | 7,000 | 31,464 | 32,942 | 38,108 | 28,707 | 100,091 | 97,795 | 98,314 | 53,259 | 96,477 | ... | ||||||||||
2010-03 | 36,937 | 64,551 | 61,774 | 39,580 | 81,253 | 35,751 | 87,788 | 41,076 | 117,835 | ... | |||||||||||
2010-04 | 21,026 | 32,422 | 46,661 | 103,442 | 89,860 | 96,976 | 51,116 | 89,352 | 50,595 | 13,981 | ... | ||||||||||
2010-05 | 8,668 | 8,920 | 116,376 | 61,586 | 148,647 | 14,288 | 46,840 | 51,205 | 82,714 | 4,240 | ... | ||||||||||
2010-06 | 12,578 | 92,156 | 44,495 | 112,868 | 79,732 | 73,743 | 61,814 | 73,713 | 23,724 | ... | |||||||||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2015-07 | 5,872 | 61,431 | 113,522 | 96,030 | 133,267 | 130,305 | 64,905 | 58,480 | 94,985 | 72,184 | ... | ||||||||||
2015-08 | 12,276 | 73,666 | 69,772 | 156,546 | 96,829 | 122,893 | 77,525 | 120,597 | 42,213 | 81,603 | ... | ||||||||||
2015-09 | 29,402 | 45,522 | 76,968 | 146,840 | 171,674 | 109,429 | 86,091 | 98,514 | 83,465 | 61,289 | ... | ||||||||||
2015-10 | 14,000 | 18,824 | 64,809 | 86,112 | 33,952 | 94,798 | 41,473 | 114,279 | 95,470 | 95,322 | ... | ||||||||||
2015-11 | 24,866 | 74,507 | 52,944 | 109,360 | 98,136 | 160,381 | 46,511 | 206,774 | 128,625 | ... | |||||||||||
2015-12 | 14,000 | 34,498 | 85,505 | 113,846 | 118,239 | 121,277 | 179,033 | 131,330 | 130,357 | 89,312 | ... | ||||||||||
2016-01 | 3,214 | 16,521 | 48,605 | 63,442 | 64,330 | 156,536 | 70,536 | 90,186 | 88,647 | 87,278 | ... | ||||||||||
2016-02 | 13,892 | 20,722 | 112,166 | 154,319 | 93,667 | 117,578 | 114,468 | 77,207 | 79,020 | 85,925 | ... | ||||||||||
2016-03 | 18,354 | 48,495 | 70,675 | 115,886 | 83,612 | 45,276 | 123,736 | 114,339 | 79,022 | 96,179 | ... | ||||||||||
2016-04 | 14,781 | 35,741 | 51,818 | 124,195 | 76,220 | 168,821 | 117,505 | 82,978 | 99,148 | 112,664 | ... | ||||||||||
2016-05 | 32,921 | 80,574 | 128,677 | 98,491 | 138,236 | 110,125 | 110,887 | 150,281 | 74,849 | ... | |||||||||||
2016-06 | 17,959 | 9,031 | 35,721 | 163,644 | 172,139 | 157,653 | 154,168 | 120,193 | 100,214 | 62,572 | ... | ||||||||||
2016-07 | 36,454 | 24,783 | 105,234 | 116,616 | 64,114 | 118,426 | 107,283 | 101,315 | 136,164 | 95,888 | ... | ||||||||||
2016-08 | 45,280 | 14,224 | 93,541 | 147,758 | 88,370 | 195,297 | 117,494 | 57,656 | 132,907 | 100,460 | ... | ||||||||||
2016-09 | 13,544 | 56,468 | 84,514 | 106,896 | 127,088 | 89,314 | 132,691 | 153,691 | 62,591 | 133,208 | ... | ||||||||||
2016-10 | 1,766 | 61,196 | 80,437 | 123,346 | 82,947 | 158,137 | 168,589 | 110,019 | 86,504 | 162,549 | ... | ||||||||||
2016-11 | 55,837 | 111,442 | 110,741 | 111,772 | 44,847 | 164,147 | 180,126 | 90,889 | 71,973 | ... | |||||||||||
2016-12 | 52,806 | 55,386 | 116,175 | 107,611 | 109,759 | 74,635 | 145,938 | 100,703 | 114,897 | ... | |||||||||||
2017-01 | 8,338 | 26,000 | 121,221 | 104,138 | 113,300 | 86,086 | 139,369 | 127,013 | 66,155 | 111,713 | ... | ||||||||||
2017-02 | 50,237 | 101,651 | 103,479 | 94,798 | 94,285 | 160,239 | 141,802 | 131,585 | 94,257 | ... | |||||||||||
2017-03 | 4,476 | 20,775 | 74,392 | 72,250 | 143,323 | 56,307 | 210,407 | 117,054 | 101,546 | 93,077 | ... | ||||||||||
2017-04 | 30,751 | 126,808 | 154,839 | 157,090 | 72,106 | 102,587 | 91,454 | 142,689 | ... | ||||||||||||
2017-05 | 3,022 | 36,811 | 54,334 | 80,437 | 81,315 | 160,838 | 180,652 | 88,441 | ... | ||||||||||||
2017-06 | 31,858 | 37,911 | 81,229 | 121,619 | 85,185 | 110,103 | ... | ||||||||||||||
2017-07 | 28,827 | 30,987 | 126,230 | 72,826 | 80,075 | 119,390 | ... | ||||||||||||||
2017-08 | 14,000 | 105,952 | 81,991 | 174,870 | ... | ||||||||||||||||
2017-09 | 18,589 | 33,317 | 86,057 | 152,144 | ... | ||||||||||||||||
2017-10 | 35,037 | 104,444 | ... | ||||||||||||||||||
2017-11 | 4,088 | 10,599 | ... | ||||||||||||||||||
2017-12 | 10,748 | ... |
prism_cum = prism.incr_to_cum()
prism_cum["Paid"].sum()
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2008-01 | 46,915 | 66,814 | 124,030 | 213,813 | 232,115 | 327,169 | 337,502 | 429,274 | ... | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | 13,957,431 | ||
2008-02 | 28,749 | 50,859 | 129,891 | 193,346 | 253,339 | 318,022 | 386,523 | 420,218 | 491,888 | ... | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | 14,514,228 | ||
2008-03 | 48,806 | 76,755 | 167,168 | 221,724 | 305,232 | 317,823 | 389,858 | 460,211 | 495,434 | ... | 11,973,601 | 11,973,601 | 11,973,601 | 11,973,601 | 11,973,601 | 11,973,601 | 11,973,601 | 11,973,601 | |||
2008-04 | 30,758 | 48,521 | 119,393 | 149,626 | 189,120 | 255,849 | 377,949 | 398,947 | 437,165 | ... | 10,173,864 | 10,173,864 | 10,173,864 | 10,173,864 | 10,173,864 | 10,173,864 | 10,173,864 | ||||
2008-05 | 38,672 | 125,646 | 146,129 | 204,529 | 316,543 | 347,897 | 370,354 | 424,131 | 517,435 | ... | 15,602,537 | 15,602,537 | 15,602,537 | 15,602,537 | 15,602,537 | 15,602,537 | |||||
2008-06 | 56,789 | 130,140 | 227,980 | 292,796 | 353,879 | 395,565 | 482,736 | 544,154 | 607,251 | ... | 11,975,412 | 11,975,412 | 11,975,412 | 11,975,412 | 11,975,412 | ||||||
2008-07 | 27,867 | 73,671 | 135,167 | 208,446 | 280,037 | 391,844 | 472,093 | 512,725 | 545,159 | ... | 11,101,871 | 11,101,871 | 11,101,871 | 11,101,871 | |||||||
2008-08 | 4,832 | 28,663 | 81,174 | 143,824 | 189,779 | 322,912 | 404,645 | 444,354 | 556,469 | 577,837 | ... | 11,889,317 | 11,889,317 | 11,889,317 | |||||||
2008-09 | 43,464 | 129,621 | 182,285 | 272,213 | 360,952 | 416,569 | 443,168 | 512,690 | 559,478 | ... | 12,257,725 | 12,257,725 | |||||||||
2008-10 | 12,488 | 34,427 | 87,815 | 140,229 | 232,315 | 278,096 | 350,338 | 433,697 | 481,291 | ... | 12,286,257 | ||||||||||
2008-11 | 45,473 | 54,888 | 133,855 | 218,682 | 258,231 | 299,241 | 373,241 | 406,498 | 442,300 | ... | |||||||||||
2008-12 | 3,640 | 13,544 | 68,336 | 155,393 | 226,080 | 280,855 | 312,267 | 356,324 | 415,772 | 447,415 | ... | ||||||||||
2009-01 | 14,021 | 59,371 | 110,579 | 146,099 | 227,754 | 282,028 | 323,566 | 397,696 | 445,657 | ... | |||||||||||
2009-02 | 10,305 | 45,331 | 82,621 | 141,394 | 208,972 | 266,561 | 381,645 | 438,786 | 504,101 | 559,120 | ... | ||||||||||
2009-03 | 48,360 | 88,861 | 163,203 | 227,741 | 277,519 | 363,110 | 445,692 | 502,141 | 590,448 | ... | |||||||||||
2009-04 | 40,943 | 88,459 | 152,483 | 180,056 | 242,690 | 296,742 | 360,047 | 421,386 | 491,791 | ... | |||||||||||
2009-05 | 16,944 | 91,422 | 155,278 | 214,543 | 294,250 | 358,107 | 417,433 | 506,250 | 556,906 | ... | |||||||||||
2009-06 | 9,655 | 53,374 | 66,180 | 145,584 | 191,803 | 238,671 | 274,905 | 310,559 | 335,235 | 361,875 | ... | ||||||||||
2009-07 | 14,828 | 63,434 | 153,961 | 208,469 | 266,350 | 331,255 | 347,971 | 394,851 | 484,572 | ... | |||||||||||
2009-08 | 42,061 | 74,308 | 138,483 | 201,926 | 267,354 | 362,786 | 454,595 | 586,499 | 653,783 | ... | |||||||||||
2009-09 | 21,000 | 48,607 | 83,286 | 120,808 | 177,113 | 219,965 | 292,369 | 346,735 | 414,277 | 485,309 | ... | ||||||||||
2009-10 | 14,000 | 76,040 | 121,174 | 218,190 | 272,546 | 293,395 | 356,915 | 435,409 | 502,850 | 524,957 | ... | ||||||||||
2009-11 | 22,027 | 86,215 | 107,052 | 140,355 | 190,949 | 270,801 | 325,670 | 437,262 | 507,735 | ... | |||||||||||
2009-12 | 38,594 | 56,496 | 156,966 | 200,832 | 302,883 | 359,784 | 393,660 | 434,076 | 488,811 | ... | |||||||||||
2010-01 | 15,192 | 68,531 | 125,925 | 182,910 | 245,085 | 329,709 | 414,668 | 517,402 | 543,897 | ... | |||||||||||
2010-02 | 7,000 | 38,464 | 71,406 | 109,514 | 138,221 | 238,312 | 336,107 | 434,422 | 487,681 | 584,158 | ... | ||||||||||
2010-03 | 36,937 | 101,487 | 163,262 | 202,842 | 284,095 | 319,846 | 407,635 | 448,711 | 566,546 | ... | |||||||||||
2010-04 | 21,026 | 53,448 | 100,108 | 203,550 | 293,410 | 390,386 | 441,502 | 530,854 | 581,449 | 595,430 | ... | ||||||||||
2010-05 | 8,668 | 17,587 | 133,963 | 195,549 | 344,196 | 358,484 | 405,324 | 456,529 | 539,244 | 543,483 | ... | ||||||||||
2010-06 | 12,578 | 104,735 | 149,230 | 262,098 | 341,830 | 415,573 | 477,388 | 551,101 | 574,825 | ... | |||||||||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2015-07 | 5,872 | 67,304 | 180,826 | 276,856 | 410,123 | 540,428 | 605,334 | 663,814 | 758,798 | 830,982 | ... | ||||||||||
2015-08 | 12,276 | 85,942 | 155,713 | 312,260 | 409,088 | 531,981 | 609,506 | 730,103 | 772,317 | 853,920 | ... | ||||||||||
2015-09 | 29,402 | 74,924 | 151,892 | 298,732 | 470,405 | 579,835 | 665,925 | 764,440 | 847,904 | 909,194 | ... | ||||||||||
2015-10 | 14,000 | 32,824 | 97,632 | 183,745 | 217,697 | 312,495 | 353,968 | 468,248 | 563,718 | 659,040 | ... | ||||||||||
2015-11 | 24,866 | 99,373 | 152,317 | 261,677 | 359,813 | 520,193 | 566,705 | 773,479 | 902,104 | ... | |||||||||||
2015-12 | 14,000 | 48,498 | 134,004 | 247,850 | 366,089 | 487,366 | 666,399 | 797,729 | 928,086 | 1,017,398 | ... | ||||||||||
2016-01 | 3,214 | 19,734 | 68,339 | 131,782 | 196,112 | 352,647 | 423,183 | 513,369 | 602,016 | 689,294 | ... | ||||||||||
2016-02 | 13,892 | 34,613 | 146,780 | 301,098 | 394,766 | 512,344 | 626,812 | 704,019 | 783,039 | 868,964 | ... | ||||||||||
2016-03 | 18,354 | 66,848 | 137,523 | 253,408 | 337,021 | 382,297 | 506,033 | 620,372 | 699,394 | 795,573 | ... | ||||||||||
2016-04 | 14,781 | 50,522 | 102,340 | 226,534 | 302,754 | 471,575 | 589,080 | 672,058 | 771,207 | 883,870 | ... | ||||||||||
2016-05 | 32,921 | 113,494 | 242,172 | 340,663 | 478,898 | 589,024 | 699,911 | 850,192 | 925,041 | ... | |||||||||||
2016-06 | 17,959 | 26,990 | 62,711 | 226,354 | 398,493 | 556,146 | 710,314 | 830,507 | 930,721 | 993,293 | ... | ||||||||||
2016-07 | 36,454 | 61,237 | 166,471 | 283,087 | 347,202 | 465,628 | 572,910 | 674,225 | 810,389 | 906,277 | ... | ||||||||||
2016-08 | 45,280 | 59,505 | 153,045 | 300,803 | 389,173 | 584,470 | 701,964 | 759,620 | 892,527 | 992,987 | ... | ||||||||||
2016-09 | 13,544 | 70,012 | 154,527 | 261,422 | 388,510 | 477,824 | 610,516 | 764,207 | 826,799 | 960,007 | ... | ||||||||||
2016-10 | 1,766 | 62,962 | 143,398 | 266,745 | 349,691 | 507,828 | 676,418 | 786,436 | 872,940 | 1,035,489 | ... | ||||||||||
2016-11 | 55,837 | 167,279 | 278,020 | 389,792 | 434,640 | 598,787 | 778,913 | 869,802 | 941,776 | ... | |||||||||||
2016-12 | 52,806 | 108,192 | 224,367 | 331,978 | 441,737 | 516,372 | 662,311 | 763,014 | 877,911 | ... | |||||||||||
2017-01 | 8,338 | 34,338 | 155,559 | 259,698 | 372,997 | 459,083 | 598,452 | 725,466 | 791,620 | 903,333 | ... | ||||||||||
2017-02 | 50,237 | 151,889 | 255,367 | 350,165 | 444,450 | 604,689 | 746,491 | 878,076 | 972,333 | ... | |||||||||||
2017-03 | 4,476 | 25,251 | 99,644 | 171,894 | 315,217 | 371,524 | 581,932 | 698,986 | 800,532 | 893,609 | ... | ||||||||||
2017-04 | 30,751 | 157,559 | 312,397 | 469,488 | 541,593 | 644,181 | 735,635 | 878,324 | ... | ||||||||||||
2017-05 | 3,022 | 39,834 | 94,168 | 174,605 | 255,919 | 416,757 | 597,409 | 685,850 | ... | ||||||||||||
2017-06 | 31,858 | 69,769 | 150,997 | 272,616 | 357,801 | 467,904 | ... | ||||||||||||||
2017-07 | 28,827 | 59,815 | 186,044 | 258,870 | 338,946 | 458,336 | ... | ||||||||||||||
2017-08 | 14,000 | 119,952 | 201,944 | 376,814 | ... | ||||||||||||||||
2017-09 | 18,589 | 51,906 | 137,963 | 290,107 | ... | ||||||||||||||||
2017-10 | 35,037 | 139,482 | ... | ||||||||||||||||||
2017-11 | 4,088 | 14,687 | ... | ||||||||||||||||||
2017-12 | 10,748 | ... |
prism_incr = prism_cum.cum_to_incr()
prism_incr["Paid"].sum()
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2008-01 | 46,915 | 19,899 | 57,216 | 89,783 | 18,302 | 95,054 | 10,332 | 91,772 | ... | ||||||||||||
2008-02 | 28,749 | 22,109 | 79,033 | 63,455 | 59,993 | 64,683 | 68,502 | 33,695 | 71,670 | ... | |||||||||||
2008-03 | 48,806 | 27,949 | 90,413 | 54,557 | 83,507 | 12,591 | 72,035 | 70,353 | 35,223 | ... | |||||||||||
2008-04 | 30,758 | 17,763 | 70,872 | 30,233 | 39,494 | 66,729 | 122,100 | 20,998 | 38,218 | ... | |||||||||||
2008-05 | 38,672 | 86,974 | 20,483 | 58,400 | 112,015 | 31,354 | 22,457 | 53,778 | 93,303 | ... | |||||||||||
2008-06 | 56,789 | 73,351 | 97,840 | 64,816 | 61,083 | 41,685 | 87,172 | 61,418 | 63,097 | ... | |||||||||||
2008-07 | 27,867 | 45,804 | 61,495 | 73,279 | 71,591 | 111,807 | 80,249 | 40,632 | 32,434 | ... | |||||||||||
2008-08 | 4,832 | 23,831 | 52,511 | 62,649 | 45,955 | 133,133 | 81,733 | 39,709 | 112,115 | 21,367 | ... | ||||||||||
2008-09 | 43,464 | 86,157 | 52,664 | 89,928 | 88,738 | 55,617 | 26,599 | 69,522 | 46,788 | ... | |||||||||||
2008-10 | 12,488 | 21,939 | 53,388 | 52,415 | 92,086 | 45,781 | 72,242 | 83,359 | 47,594 | ... | |||||||||||
2008-11 | 45,473 | 9,416 | 78,967 | 84,826 | 39,549 | 41,011 | 74,000 | 33,257 | 35,802 | ... | |||||||||||
2008-12 | 3,640 | 9,905 | 54,792 | 87,057 | 70,686 | 54,775 | 31,412 | 44,057 | 59,448 | 31,643 | ... | ||||||||||
2009-01 | 14,021 | 45,350 | 51,208 | 35,520 | 81,655 | 54,275 | 41,538 | 74,129 | 47,962 | ... | |||||||||||
2009-02 | 10,305 | 35,026 | 37,289 | 58,773 | 67,579 | 57,589 | 115,083 | 57,142 | 65,315 | 55,019 | ... | ||||||||||
2009-03 | 48,360 | 40,502 | 74,342 | 64,538 | 49,778 | 85,591 | 82,582 | 56,449 | 88,307 | ... | |||||||||||
2009-04 | 40,943 | 47,517 | 64,024 | 27,573 | 62,634 | 54,051 | 63,305 | 61,339 | 70,406 | ... | |||||||||||
2009-05 | 16,944 | 74,478 | 63,856 | 59,266 | 79,707 | 63,857 | 59,326 | 88,817 | 50,656 | ... | |||||||||||
2009-06 | 9,655 | 43,720 | 12,805 | 79,404 | 46,219 | 46,868 | 36,234 | 35,654 | 24,676 | 26,641 | ... | ||||||||||
2009-07 | 14,828 | 48,605 | 90,527 | 54,508 | 57,881 | 64,905 | 16,717 | 46,880 | 89,721 | ... | |||||||||||
2009-08 | 42,061 | 32,247 | 64,174 | 63,443 | 65,428 | 95,432 | 91,809 | 131,904 | 67,284 | ... | |||||||||||
2009-09 | 21,000 | 27,607 | 34,679 | 37,523 | 56,305 | 42,851 | 72,404 | 54,366 | 67,543 | 71,032 | ... | ||||||||||
2009-10 | 14,000 | 62,040 | 45,134 | 97,016 | 54,356 | 20,848 | 63,521 | 78,494 | 67,441 | 22,107 | ... | ||||||||||
2009-11 | 22,027 | 64,189 | 20,836 | 33,303 | 50,594 | 79,852 | 54,870 | 111,592 | 70,473 | ... | |||||||||||
2009-12 | 38,594 | 17,902 | 100,470 | 43,866 | 102,051 | 56,901 | 33,876 | 40,416 | 54,734 | ... | |||||||||||
2010-01 | 15,192 | 53,338 | 57,394 | 56,985 | 62,175 | 84,624 | 84,959 | 102,734 | 26,495 | ... | |||||||||||
2010-02 | 7,000 | 31,464 | 32,942 | 38,108 | 28,707 | 100,091 | 97,795 | 98,314 | 53,259 | 96,477 | ... | ||||||||||
2010-03 | 36,937 | 64,551 | 61,774 | 39,580 | 81,253 | 35,751 | 87,788 | 41,076 | 117,835 | ... | |||||||||||
2010-04 | 21,026 | 32,422 | 46,661 | 103,442 | 89,860 | 96,976 | 51,116 | 89,352 | 50,595 | 13,981 | ... | ||||||||||
2010-05 | 8,668 | 8,920 | 116,376 | 61,586 | 148,647 | 14,288 | 46,840 | 51,205 | 82,714 | 4,240 | ... | ||||||||||
2010-06 | 12,578 | 92,156 | 44,495 | 112,868 | 79,732 | 73,743 | 61,814 | 73,713 | 23,724 | ... | |||||||||||
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2015-07 | 5,872 | 61,431 | 113,522 | 96,030 | 133,267 | 130,305 | 64,905 | 58,480 | 94,985 | 72,184 | ... | ||||||||||
2015-08 | 12,276 | 73,666 | 69,772 | 156,546 | 96,829 | 122,893 | 77,525 | 120,597 | 42,213 | 81,603 | ... | ||||||||||
2015-09 | 29,402 | 45,522 | 76,968 | 146,840 | 171,674 | 109,429 | 86,091 | 98,514 | 83,465 | 61,289 | ... | ||||||||||
2015-10 | 14,000 | 18,824 | 64,809 | 86,112 | 33,952 | 94,798 | 41,473 | 114,279 | 95,470 | 95,322 | ... | ||||||||||
2015-11 | 24,866 | 74,507 | 52,944 | 109,360 | 98,136 | 160,381 | 46,511 | 206,774 | 128,625 | ... | |||||||||||
2015-12 | 14,000 | 34,498 | 85,505 | 113,846 | 118,239 | 121,277 | 179,033 | 131,330 | 130,357 | 89,312 | ... | ||||||||||
2016-01 | 3,214 | 16,521 | 48,605 | 63,442 | 64,330 | 156,536 | 70,536 | 90,186 | 88,647 | 87,278 | ... | ||||||||||
2016-02 | 13,892 | 20,722 | 112,166 | 154,319 | 93,667 | 117,578 | 114,468 | 77,207 | 79,020 | 85,925 | ... | ||||||||||
2016-03 | 18,354 | 48,495 | 70,675 | 115,886 | 83,612 | 45,276 | 123,736 | 114,339 | 79,022 | 96,179 | ... | ||||||||||
2016-04 | 14,781 | 35,741 | 51,818 | 124,195 | 76,220 | 168,821 | 117,505 | 82,978 | 99,148 | 112,664 | ... | ||||||||||
2016-05 | 32,921 | 80,574 | 128,677 | 98,491 | 138,236 | 110,125 | 110,887 | 150,281 | 74,849 | ... | |||||||||||
2016-06 | 17,959 | 9,031 | 35,721 | 163,644 | 172,139 | 157,653 | 154,168 | 120,193 | 100,214 | 62,572 | ... | ||||||||||
2016-07 | 36,454 | 24,783 | 105,234 | 116,616 | 64,114 | 118,426 | 107,283 | 101,315 | 136,164 | 95,888 | ... | ||||||||||
2016-08 | 45,280 | 14,224 | 93,541 | 147,758 | 88,370 | 195,297 | 117,494 | 57,656 | 132,907 | 100,460 | ... | ||||||||||
2016-09 | 13,544 | 56,468 | 84,514 | 106,896 | 127,088 | 89,314 | 132,691 | 153,691 | 62,591 | 133,208 | ... | ||||||||||
2016-10 | 1,766 | 61,196 | 80,437 | 123,346 | 82,947 | 158,137 | 168,589 | 110,019 | 86,504 | 162,549 | ... | ||||||||||
2016-11 | 55,837 | 111,442 | 110,741 | 111,772 | 44,847 | 164,147 | 180,126 | 90,889 | 71,973 | ... | |||||||||||
2016-12 | 52,806 | 55,386 | 116,175 | 107,611 | 109,759 | 74,635 | 145,938 | 100,703 | 114,897 | ... | |||||||||||
2017-01 | 8,338 | 26,000 | 121,221 | 104,138 | 113,300 | 86,086 | 139,369 | 127,013 | 66,155 | 111,713 | ... | ||||||||||
2017-02 | 50,237 | 101,651 | 103,479 | 94,798 | 94,285 | 160,239 | 141,802 | 131,585 | 94,257 | ... | |||||||||||
2017-03 | 4,476 | 20,775 | 74,392 | 72,250 | 143,323 | 56,307 | 210,407 | 117,054 | 101,546 | 93,077 | ... | ||||||||||
2017-04 | 30,751 | 126,808 | 154,839 | 157,090 | 72,106 | 102,587 | 91,454 | 142,689 | ... | ||||||||||||
2017-05 | 3,022 | 36,811 | 54,334 | 80,437 | 81,315 | 160,838 | 180,652 | 88,441 | ... | ||||||||||||
2017-06 | 31,858 | 37,911 | 81,229 | 121,619 | 85,185 | 110,103 | ... | ||||||||||||||
2017-07 | 28,827 | 30,987 | 126,230 | 72,826 | 80,075 | 119,390 | ... | ||||||||||||||
2017-08 | 14,000 | 105,952 | 81,991 | 174,870 | ... | ||||||||||||||||
2017-09 | 18,589 | 33,317 | 86,057 | 152,144 | ... | ||||||||||||||||
2017-10 | 35,037 | 104,444 | ... | ||||||||||||||||||
2017-11 | 4,088 | 10,599 | ... | ||||||||||||||||||
2017-12 | 10,748 | ... |
By default (and in concert with the pandas
philosophy), the methods associated with the Triangle
class strive for immutability. This means that the incr_to_cum
and cum_to_incr
methods will return new a new triangle object that must be assigned, or it is thrown away. Many of the chainladder.Triangle
methods have an inplace
argument, or alternatively you can just use variable reassignment to store the transformed triangle object.
# This works
prism.incr_to_cum(inplace=True)
# So does this
prism = prism.incr_to_cum()
When dealing with triangles that have an origin
axis, development
axis, or both at a monthly or quarterly grain, the triangle can be summarized to a higher grain using the grain
method.
The grain to which you want your triangle converted, specified as “OxDy” where “x” and “y” can take on values of “M”, “Q”, or “Y”. For example:
grain(OYDY)
for Origin Year x Development Year.grain(OQDM)
for Origin Quarter x Development Month.
prism_OYDY = prism.grain("OYDY")
prism_OYDY["Paid"].sum()
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
2008 | 3,404,254 | 11,191,085 | 74,613,012 | 150,342,751 | 150,982,873 | 151,152,726 | 151,228,872 | 151,264,806 | 151,277,217 | 151,284,217 |
2009 | 3,609,385 | 11,002,927 | 80,726,352 | 156,970,789 | 157,599,460 | 157,697,094 | 157,736,386 | 157,743,386 | 157,748,735 | |
2010 | 4,067,321 | 12,396,777 | 74,210,043 | 161,049,586 | 161,641,453 | 161,787,135 | 161,859,565 | 161,870,156 | ||
2011 | 4,125,232 | 13,183,144 | 81,239,771 | 161,412,913 | 162,187,629 | 162,417,460 | 162,490,681 | |||
2012 | 4,584,036 | 14,001,178 | 77,794,522 | 152,118,384 | 152,588,090 | 152,819,473 | ||||
2013 | 4,889,623 | 14,607,742 | 84,418,503 | 161,110,312 | 161,673,036 | |||||
2014 | 5,546,158 | 16,408,126 | 77,256,792 | 154,969,931 | ||||||
2015 | 5,909,029 | 17,427,611 | 80,914,580 | |||||||
2016 | 6,080,962 | 18,588,057 | ||||||||
2017 | 6,396,536 |
Depending on the type of analysis being done, it may be more convenient to look at a triangle with its development
axis expressed as a valuation rather than an age. This is also what the Schedule Ps look like. To do this, Triangle
has two methods for toggling between a development triangle and a valuation triangle. The methods are dev_to_val
and its inverse val_to_dev
.
prism_OYDY_val = prism_OYDY.dev_to_val()
prism_OYDY_val["Paid"].sum()
2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | |
---|---|---|---|---|---|---|---|---|---|---|
2008 | 3,404,254 | 11,191,085 | 74,613,012 | 150,342,751 | 150,982,873 | 151,152,726 | 151,228,872 | 151,264,806 | 151,277,217 | 151,284,217 |
2009 | 3,609,385 | 11,002,927 | 80,726,352 | 156,970,789 | 157,599,460 | 157,697,094 | 157,736,386 | 157,743,386 | 157,748,735 | |
2010 | 4,067,321 | 12,396,777 | 74,210,043 | 161,049,586 | 161,641,453 | 161,787,135 | 161,859,565 | 161,870,156 | ||
2011 | 4,125,232 | 13,183,144 | 81,239,771 | 161,412,913 | 162,187,629 | 162,417,460 | 162,490,681 | |||
2012 | 4,584,036 | 14,001,178 | 77,794,522 | 152,118,384 | 152,588,090 | 152,819,473 | ||||
2013 | 4,889,623 | 14,607,742 | 84,418,503 | 161,110,312 | 161,673,036 | |||||
2014 | 5,546,158 | 16,408,126 | 77,256,792 | 154,969,931 | ||||||
2015 | 5,909,029 | 17,427,611 | 80,914,580 | |||||||
2016 | 6,080,962 | 18,588,057 | ||||||||
2017 | 6,396,536 |
When working with real-world data, the triangles can have holes, such as missing evluation(s), or no losses in certain origin(s). In these cases, it doesn’t make sense to include empty accident periods or development ages. For example, in the prism
dataset, the “Home” line has its latest accidents through 2016, and have no payments in development age ‘12’. Sometimes, dropping the non-applicable fields is usefule with the dropna()
method.
prism_OYDY.loc["Home"]["Paid"]
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
2008 | 1,129,305 | 61,658,874 | 136,520,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | |
2009 | 187,292 | 67,134,599 | 142,267,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | ||
2010 | 620,603 | 59,082,456 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | |||
2011 | 503,296 | 65,048,051 | 143,971,618 | 144,251,618 | 144,251,618 | 144,251,618 | ||||
2012 | 599,277 | 60,536,642 | 133,412,416 | 133,412,416 | 133,412,416 | |||||
2013 | 536,303 | 66,443,157 | 141,645,782 | 141,645,782 | ||||||
2014 | 965,973 | 57,394,263 | 133,542,848 | |||||||
2015 | 371,015 | 59,047,107 | ||||||||
2016 | 640,179 | |||||||||
2017 |
Let’s see what happens if we have no data for 2011.
prism_df_2011 = prism_df.copy()
prism_df_2011.loc[
(prism_df_2011["AccidentDate"] >= "2011-01-01")
& (prism_df_2011["AccidentDate"] < "2012-01-01"),
"Paid",
] = None # Let's assume we hav no payments for losses occurred in 2011
prism_2011 = cl.Triangle(
data=prism_df_2011,
origin="AccidentDate",
origin_format="%Y-%m-%d",
development="PaymentDate",
development_format="%Y-%m-%d",
columns=["Paid", "Incurred"],
index=["Line", "Type"],
cumulative=False,
)
prism_2011.incr_to_cum(inplace=True)
prism_2011_OYDY = prism_2011.grain("OYDY")
prism_2011_OYDY.loc["Home"]["Paid"]
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
2008 | 1,129,305 | 61,658,874 | 136,520,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | |
2009 | 187,292 | 67,134,599 | 142,267,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | ||
2010 | 620,603 | 59,082,456 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | |||
2011 | ||||||||||
2012 | 599,277 | 60,536,642 | 133,412,416 | 133,412,416 | 133,412,416 | |||||
2013 | 536,303 | 66,443,157 | 141,645,782 | 141,645,782 | ||||||
2014 | 965,973 | 57,394,263 | 133,542,848 | |||||||
2015 | 371,015 | 59,047,107 | ||||||||
2016 | 640,179 | |||||||||
2017 |
Note that the dropna()
method will retain empty periods if they are surrounded by non-empty periods with valid data.
prism_2011_OYDY_droppedna = prism_2011_OYDY.loc["Home"].dropna()
prism_2011_OYDY_droppedna.loc["Home"]["Paid"]
24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|
2008 | 1,129,305 | 61,658,874 | 136,520,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 |
2009 | 187,292 | 67,134,599 | 142,267,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | |
2010 | 620,603 | 59,082,456 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | ||
2011 | |||||||||
2012 | 599,277 | 60,536,642 | 133,412,416 | 133,412,416 | 133,412,416 | ||||
2013 | 536,303 | 66,443,157 | 141,645,782 | 141,645,782 | |||||
2014 | 965,973 | 57,394,263 | 133,542,848 | ||||||
2015 | 371,015 | 59,047,107 | |||||||
2016 | 640,179 |
Commutative Properties of Triangle Methods¶
Where it makes sense, which is in most cases, the methods described above are commutative and can be applied in any order.
print("Commutative?", prism.sum().latest_diagonal == prism.latest_diagonal.sum())
print("Commutative?", prism.loc["Home"].link_ratio == prism.link_ratio.loc["Home"])
Commutative? True
Commutative? True
Triangle Imports and Exports¶
To the extent the Triangle
can be expressed as a pandas.DataFrame
, you can use any of the pandas IO to send the data in and out. Note that converting to pandas is a one-way ticket with no inverse functions.
Another useful function is to copy the triangle and put it in the clipboard so we can paste it elsewhere (such as Excel):
prism_OYDY.loc["Home", "Paid"]
12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 | 108 | 120 | |
---|---|---|---|---|---|---|---|---|---|---|
2008 | 1,129,305 | 61,658,874 | 136,520,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | 136,800,554 | |
2009 | 187,292 | 67,134,599 | 142,267,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | 142,547,946 | ||
2010 | 620,603 | 59,082,456 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | 144,757,200 | |||
2011 | 503,296 | 65,048,051 | 143,971,618 | 144,251,618 | 144,251,618 | 144,251,618 | ||||
2012 | 599,277 | 60,536,642 | 133,412,416 | 133,412,416 | 133,412,416 | |||||
2013 | 536,303 | 66,443,157 | 141,645,782 | 141,645,782 | ||||||
2014 | 965,973 | 57,394,263 | 133,542,848 | |||||||
2015 | 371,015 | 59,047,107 | ||||||||
2016 | 640,179 | |||||||||
2017 |
prism_OYDY.loc["Home", "Paid"].to_clipboard()
Try to paste it elsewhere.
Alternatively, if you want to store the triangle elsewhere but be able to reconstitute a triangle out of it later, then you can use:
Triangle.to_json
and its inversecl.read_json
for json formatTriangle.to_pickle
and its inversecl.read_pickle
for pickle format
These have the added benefit of working on multi-dimensional triangles that don’t fit into a DataFrame.
Exercises¶
prism = cl.Triangle(
data=prism_df,
origin="AccidentDate",
development="PaymentDate",
columns=["Paid", "Incurred"],
index=["Line", "Type"], # multiple indices
cumulative=False,
).incr_to_cum()
prism
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OMDM |
Shape: | (2, 2, 120, 120) |
Index: | [Line, Type] |
Columns: | [Paid, Incurred] |
What is the case incurred activity for calendar periods in 2015Q2 (March, April, and May in 2015) by “Line”?
incr_by_line = prism.groupby("Line").sum().cum_to_incr()["Incurred"].dev_to_val()
incr_by_line[
(incr_by_line.valuation >= "2015-04-01") & (incr_by_line.valuation < "2015-07-01")
].sum("origin").to_frame(origin_as_datetime=True).astype(int)
development | 2015-04 | 2015-05 | 2015-06 |
---|---|---|---|
Line | |||
Auto | 1883976 | 1704338 | 1692254 |
Home | 10367939 | 10813821 | 14537617 |
For accident year 2015, what proportion of our Paid amounts come from each “Type” of claims?
prism_OYDY = prism.grain("OYDY")
prism_OYDY
Triangle Summary | |
---|---|
Valuation: | 2017-12 |
Grain: | OYDY |
Shape: | (2, 2, 10, 10) |
Index: | [Line, Type] |
Columns: | [Paid, Incurred] |
by_type = (
prism_OYDY.latest_diagonal[prism_OYDY.origin == "2015"]["Paid"]
.groupby("Type")
.sum()
.to_frame(origin_as_datetime=True)
)
by_type / by_type.sum()
Type
Dwelling 0.729746
PD 0.270254
dtype: float64