diff --git a/chainladder/core/tests/test_triangle.py b/chainladder/core/tests/test_triangle.py index 6bfc432b..9183ecad 100644 --- a/chainladder/core/tests/test_triangle.py +++ b/chainladder/core/tests/test_triangle.py @@ -1448,6 +1448,75 @@ def test_single_valuation_date_preserves_exact_date(): assert triangle.valuation_date == pd.Timestamp(val_date_exp) assert triangle.development_grain == 'M' assert int(triangle.valuation_date.strftime('%Y%m')) == 202510 + + +def test_1d_annual_valuation_date() -> None: + year_data = [ + [1998, 2008, 900000, 890000], + [1999, 2008, 1200000, 1170000], + [2000, 2008, 1300000, 1265000], + [2001, 2008, 1800000, 1600000], + [2002, 2008, 1450000, 1200000], + ] + year_df = pd.DataFrame( + data=year_data, columns=["origin", "dev", "revenue", "expense"] + ) + tri = cl.Triangle( + data=year_df, + origin="origin", + development="dev", + columns="expense", + development_format="%Y", + cumulative=True, + ) + assert pd.to_datetime(tri.valuation_date).date() == pd.Timestamp("2008-12-31").date() + assert tri.development_grain == "Y" + +def test_1d_monthly_valuation_date() -> None: + year_data = [ + [1998, "2008-01", 900000, 890000], + [1999, "2008-01", 1200000, 1170000], + [2000, "2008-01", 1300000, 1265000], + [2001, "2008-01", 1800000, 1600000], + [2002, "2008-01", 1450000, 1200000], + ] + year_df = pd.DataFrame( + data=year_data, columns=["origin", "dev", "revenue", "expense"] + ) + tri = cl.Triangle( + data=year_df, + origin="origin", + development="dev", + columns="expense", + development_format="%Y-%m", + cumulative=True, + ) + assert pd.to_datetime(tri.valuation_date).date() == pd.Timestamp("2008-01-31").date() + assert tri.development_grain == "M" + +def test_1d_monthly_valuation_date_expanded_dev_date() -> None: + year_df = pd.DataFrame( + { + "origin": [1998, 1999, 2000, 2001, 2002], + "dev": [2008.0, 2008.0, 2008.0, 2008.0, 2008.0], + "expense": [890000, 1170000, 1265000, 1600000, 1200000], + } + ) + tri = cl.Triangle( + data=year_df, + origin="origin", + development="dev", + columns="expense", + development_format="%Y", + cumulative=True, + ) + assert pd.to_datetime(tri.valuation_date).date() == pd.Timestamp("2008-12-31").date() + assert tri.development_grain == "Y" + +def test_friedland_gl_self_insurer_grain() -> None: + data_valuation_date = cl.load_sample('friedland_gl_self_insurer').valuation_date + assert pd.to_datetime(data_valuation_date).date() == pd.Timestamp("2008-12-31").date() + def test_OXDX_triangle(): for x in [12,6,3,1]: diff --git a/chainladder/core/triangle.py b/chainladder/core/triangle.py index ffa380b9..69652574 100644 --- a/chainladder/core/triangle.py +++ b/chainladder/core/triangle.py @@ -482,7 +482,18 @@ def __init__( ) if len(development_date.unique()) == 1: - if len(data) == 1 and self.origin_grain.split("-")[0] in ["Y", "A"]: + # checks if development is not empty, and if ithas any non-yearly values + dev_has_no_month = not development or all( + pd.to_numeric(data[col], errors="coerce") + .astype("Int64") + .astype(str) + .str.fullmatch(r"\d{4}") + .all() + for col in development + ) + + if len(data) == 1 or dev_has_no_month: + # if development has no monthly values, match origin self.development_grain = self.origin_grain else: dev_date = pd.to_datetime(development_date.iloc[0]) @@ -1466,10 +1477,11 @@ def _val_dev(self, sign, inplace=False): ddims = len(ddims.drop_duplicates()) if ddims == 1 and sign == -1: ddims = len(obj.odims) - if obj.values.density > 0 and obj.values.coords[-1].min() < 0: - obj.values.coords[-1] = obj.values.coords[-1] - min( - obj.values.coords[-1].min(), min_slide - ) + if obj.values.density > 0: + if obj.values.coords[-1].min() < 0: + obj.values.coords[-1] = obj.values.coords[-1] - min( + obj.values.coords[-1].min(), min_slide + ) ddims = np.max([np.max(obj.values.coords[-1]) + 1, ddims]) obj.values.shape = tuple(list(obj.shape[:-1]) + [ddims]) if options.AUTO_SPARSE == False or backend == "cupy": diff --git a/chainladder/utils/data/_manifest.py b/chainladder/utils/data/_manifest.py index ac9d2528..e5c0cce0 100644 --- a/chainladder/utils/data/_manifest.py +++ b/chainladder/utils/data/_manifest.py @@ -160,7 +160,6 @@ "Paid Claims", ], "cumulative": True, - "development_format": "%Y-12-31", }, "friedland_med_mal": { "origin": "Accident Year",