Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions chainladder/development/outstanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import numpy as np
import pandas as pd
import warnings

if TYPE_CHECKING:
from chainladder.core import Triangle
Expand Down Expand Up @@ -168,17 +169,28 @@ def fit(self, X, y=None, sample_weight=None):
Development(n_periods=self.case_n_periods).fit(self.X_.sum(0).sum(1)).w_
)

case_to_prior_case_naned = self.case_to_prior_case_ * self.case_w_
case_to_prior_case_naned.values = num_to_nan(case_to_prior_case_naned.values)

self.case_ldf_ = self.case_to_prior_case_.mean(2) # this has the wrong value
self.case_ldf_.values = case_to_prior_case_naned.mean(axis=2).values

paid_to_prior_case_naned = self.paid_to_prior_case_ * self.paid_w_
paid_to_prior_case_naned.values = num_to_nan(paid_to_prior_case_naned.values)
with warnings.catch_warnings():
Comment thread
henrydingliu marked this conversation as resolved.
Resolved
warnings.filterwarnings(
"ignore",
category=RuntimeWarning,
message=".*empty slice.*",
)
warnings.filterwarnings(
"ignore",
category=RuntimeWarning,
message=".*All-NaN slice.*",
)
case_to_prior_case_naned = self.case_to_prior_case_ * self.case_w_
case_to_prior_case_naned.values = num_to_nan(
case_to_prior_case_naned.values
)
self.case_ldf_ = case_to_prior_case_naned.mean(axis=2).fillna(1.0)

self.paid_ldf_ = self.paid_to_prior_case_.mean(2) # this has the wrong value
self.paid_ldf_.values = paid_to_prior_case_naned.mean(axis=2).values
paid_to_prior_case_naned = self.paid_to_prior_case_ * self.paid_w_
paid_to_prior_case_naned.values = num_to_nan(
paid_to_prior_case_naned.values
)
self.paid_ldf_ = paid_to_prior_case_naned.mean(axis=2).fillzero()

self.ldf_ = self._set_ldf(self.X_).set_backend(backend)

Expand Down Expand Up @@ -271,9 +283,8 @@ def case_to_prior_case_(self):
paid_tri = paid_tri.groupby(self.groupby).sum()
incurred_tri = incurred_tri.groupby(self.groupby).sum()

out = (incurred_tri - paid_tri).iloc[..., 1:] / (incurred_tri - paid_tri).iloc[
..., :-1
].values
prior_case = num_to_nan((incurred_tri - paid_tri).iloc[..., :-1].values)
out = (incurred_tri - paid_tri).iloc[..., 1:] / prior_case
out.is_pattern = True
out.is_cumulative = False

Expand All @@ -288,10 +299,8 @@ def paid_to_prior_case_(self):
paid_tri = paid_tri.groupby(self.groupby).sum()
incurred_tri = incurred_tri.groupby(self.groupby).sum()

out = (
paid_tri.cum_to_incr().iloc[..., 1:]
/ (incurred_tri - paid_tri).iloc[..., :-1].values
)
prior_case = num_to_nan((incurred_tri - paid_tri).iloc[..., :-1].values)
out = paid_tri.cum_to_incr().iloc[..., 1:] / prior_case
out.is_pattern = True

return out
Expand Down
30 changes: 30 additions & 0 deletions chainladder/development/tests/test_outstanding.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,33 @@ def test_unweighted_ratios_preserved_when_n_periods_set():
assert np.allclose(
m.case_to_prior_case_.values, m_full.case_to_prior_case_.values, equal_nan=True
)


def test_case_outstanding_zero_case_reserve_warning():
import warnings

xyz = cl.load_sample("friedland_xyz_auto_bi")
with warnings.catch_warnings():
warnings.filterwarnings("error", category=RuntimeWarning)
model = cl.CaseOutstanding(
paid_to_incurred=("Paid Claims", "Reported Claims")
).fit(xyz)
assert model.paid_ldf_ is not None
assert not model.case_ldf_.to_frame().isna().any().any()


def test_case_outstanding_synthetic_zero_prior_case_warning():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use test fixture?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do, I will pull the synthetic zero-case setup into a pytest fixture to keep the test body clean

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i meant the genins sample

import warnings

p = cl.load_sample("genins")
p.columns = ["paid"]
i = p.copy()
i.columns = ["incurred"]
i.values = p.values + 100
# Force case to zero at earlier development maturity
i.values[..., 2] = p.values[..., 2]
tri = cl.concat((p, i), 1)
with warnings.catch_warnings():
warnings.filterwarnings("error", category=RuntimeWarning)
m_zero = cl.CaseOutstanding(paid_to_incurred=("paid", "incurred")).fit(tri)
assert not m_zero.case_ldf_.to_frame().isna().any().any()
Loading