diff --git a/chainladder/core/io.py b/chainladder/core/io.py index 127c1f77..b72f0d1b 100644 --- a/chainladder/core/io.py +++ b/chainladder/core/io.py @@ -1,11 +1,14 @@ +""" +Support Triangle I/O capabilities. +""" # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at https://mozilla.org/MPL/2.0/. +import dill +import json import pandas as pd + from sklearn.base import BaseEstimator -import json -import joblib -import dill class TriangleIO: diff --git a/chainladder/development/base.py b/chainladder/development/base.py index 47c13081..49c1192e 100644 --- a/chainladder/development/base.py +++ b/chainladder/development/base.py @@ -21,7 +21,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from chainladder.core.typing import TriangleLike + from chainladder.core import Triangle class DevelopmentBase( @@ -45,18 +45,18 @@ def fit(self, X, y=None, sample_weight=None): def _set_fit_groups( self, - X: TriangleLike - ) -> TriangleLike: + X: Triangle + ) -> Triangle: """ Used for assigning group_index in fit. Parameters ---------- - X: TriangleLike + X: Triangle Returns ------- - TriangleLike, after performing the groupby on it. + Triangle, after performing the groupby on it. """ backend = "numpy" if X.array_backend in ["sparse", "numpy"] else "cupy" @@ -383,4 +383,39 @@ def _drop(self, X): np.where(X.origin == item[0])[0][0], np.where(X.development == item[1])[0][0], ] = 0 - return arr[:, :-1] \ No newline at end of file + return arr[:, :-1] + + @staticmethod + def _param_property( + X: Triangle, + params: np.ndarray + ) -> Triangle: + """ + Wrap an array of estimated parameters in a Triangle + + Parameters + ---------- + X: Triangle + The Triangle to wrap the parameters with + + params: np.ndarray + The parameters to be wrapped + + Returns + ------- + Triangle + The wrapped parameters + + """ + from chainladder import options + + obj: Triangle = X[X.origin == X.origin.min()] + xp = X.get_array_module() + obj.values = params + obj.valuation_date = pd.to_datetime(options.ULT_VAL) + obj.is_pattern = True + obj.is_additive = True + obj.is_cumulative = False + obj.virtual_columns.columns = {} + obj._set_slicers() + return obj diff --git a/chainladder/development/incremental.py b/chainladder/development/incremental.py index a79df253..90e80777 100644 --- a/chainladder/development/incremental.py +++ b/chainladder/development/incremental.py @@ -294,18 +294,4 @@ def transform(self, X): X_new = X.copy() for item in ["ldf_", "w_", "zeta_", "incremental_", "tri_zeta", "fit_zeta_", "sample_weight"]: X_new.__dict__[item] = self.__dict__[item] - return X_new - - def _param_property(self, factor, params): - from chainladder import options - - obj = factor[factor.origin == factor.origin.min()] - xp = factor.get_array_module() - obj.values = params - obj.valuation_date = pd.to_datetime(options.ULT_VAL) - obj.is_pattern = True - obj.is_additive = True - obj.is_cumulative = False - obj.virtual_columns.columns = {} - obj._set_slicers() - return obj + return X_new \ No newline at end of file diff --git a/chainladder/utils/tests/test_utilities.py b/chainladder/utils/tests/test_utilities.py index c296507e..9c4615b2 100644 --- a/chainladder/utils/tests/test_utilities.py +++ b/chainladder/utils/tests/test_utilities.py @@ -420,6 +420,42 @@ def test_read_pickle_triangle(raa: Triangle, tmp_path: Path) -> None: assert cl.read_pickle(str(pkl_path)) == raa +def test_triangle_to_pickle( + raa: Triangle, + clrd: Triangle, + tmp_path: Path +) -> None: + """ + Dump a pickle of a triangle and read it back in. The read-in triangle should + equal the one that was dumped. + + Parameters + ---------- + raa: Triangle + The raa sample data set Triangle. + clrd: Triangle + The clrd sample data set Triangle. + tmp_path: Path + The builtin pytest tmp_path fixture, provides a temporary path to dump the pickle to. + + Returns + ------- + None + + """ + # Single-dimension case. + raa_path = tmp_path / "raa.pkl" + raa.to_pickle(str(raa_path)) + assert raa_path.is_file() + assert cl.read_pickle(str(raa_path)) == raa + + # Multidimensional case. + clrd_path = tmp_path / "clrd.pkl" + clrd.to_pickle(str(clrd_path)) + assert clrd_path.is_file() + assert cl.read_pickle(str(clrd_path)) == clrd + + def test_read_pickle_estimator(raa: Triangle, tmp_path: Path) -> None: """ Create an estimator, dump a pickle of it, and then read it back in. The ingested pickle should result