diff --git a/chainladder/core/tests/test_triangle.py b/chainladder/core/tests/test_triangle.py index 1a0857e79..e0ba3caa0 100644 --- a/chainladder/core/tests/test_triangle.py +++ b/chainladder/core/tests/test_triangle.py @@ -164,8 +164,7 @@ def test_printer(raa): def test_value_order(clrd): a = clrd[["CumPaidLoss", "BulkLoss"]] b = clrd[["BulkLoss", "CumPaidLoss"]] - xp = a.get_array_module() - xp.testing.assert_array_equal(a.values[:, -1], b.values[:, 0]) + assert a.iloc[:, -1] == b.iloc[:, 0] def test_trend(raa, atol): @@ -436,7 +435,7 @@ def test_groupby_agg_auto_sparse(prism: Triangle) -> None: assert result_default == result_no_sparse -def test_auto_sparse_disabled_returns_self(prism: Triangle) -> None: +def test_auto_sparse_disabled_returns_self(prism_convert: Triangle) -> None: """ When cl.options.AUTO_SPARSE is False, _auto_sparse() returns the triangle unchanged without switching backends. @@ -450,7 +449,7 @@ def test_auto_sparse_disabled_returns_self(prism: Triangle) -> None: ------- None """ - dense = prism.set_backend("numpy") + dense = prism_convert.set_backend("numpy") cl.options.set_option("AUTO_SPARSE", False) try: result = dense._auto_sparse() diff --git a/chainladder/development/learning.py b/chainladder/development/learning.py index 0d9ab2ac3..01b76fb35 100644 --- a/chainladder/development/learning.py +++ b/chainladder/development/learning.py @@ -250,11 +250,14 @@ def _prep_X_ml(self, X): return df def _prep_w_ml(self,X,sample_weight=None): - weight_base = (~np.isnan(X.values)).astype(float) + #scikit-learn requires a dense sample_weight + backend = "cupy" if X.array_backend == "cupy" else "numpy" + obj = X.set_backend(backend) + weight_base = (~np.isnan(obj.values)).astype(float) weight = weight_base.copy() - weight = weight * TriangleWeight(drop=self.drop,drop_valuation=self.drop_valuation).fit(X).w_.fillzero().values + weight = weight * TriangleWeight(drop=self.drop,drop_valuation=self.drop_valuation).fit(obj).w_.fillzero().values if sample_weight is not None: - weight = weight * sample_weight.values + weight = weight * sample_weight.set_backend(backend).values return weight.flatten()[weight_base.flatten()>0] def fit(self, X, y=None, sample_weight=None): diff --git a/chainladder/development/tests/test_development.py b/chainladder/development/tests/test_development.py index d92a05935..f8bc6687b 100644 --- a/chainladder/development/tests/test_development.py +++ b/chainladder/development/tests/test_development.py @@ -22,20 +22,23 @@ def __init__(self,dev): def fit(self, X, y: None = None, sample_weight: None = None): if hasattr(X,'age_to_age'): - super().fit(X.incr_to_cum().age_to_age) - xp = X.get_array_module() - indices = X.values.shape[0] - columns = X.values.shape[1] - origins = X.age_to_age.values.shape[2] - reg_x = X.incr_to_cum().values[...,:origins,:-1] - reg_y = X.incr_to_cum().values[...,:origins,1:] + #following precedent _set_fit_groups() from DevelopmentBase + backend = "numpy" if X.array_backend in ["sparse", "numpy"] else "cupy" + obj = X.set_backend(backend) + super().fit(obj.incr_to_cum().age_to_age) + xp = obj.get_array_module() + indices = obj.values.shape[0] + columns = obj.values.shape[1] + origins = obj.age_to_age.values.shape[2] + reg_x = obj.incr_to_cum().values[...,:origins,:-1] + reg_y = obj.incr_to_cum().values[...,:origins,1:] dev_len = reg_x.shape[3] average_param = self._cascade_param(dev_len, self.average, "volume") average_param = np.tile(average_param,(indices,columns,1,1)) params = cl.WeightedRegression(axis=2, thru_orig=True, xp=xp).fit( reg_x, reg_y, self.w_.values, average_param ) - self.ldf_ = self.dev._param_property(X, params.slope_.swapaxes(2, 3), 0) + self.ldf_ = self.dev._param_property(obj, params.slope_.swapaxes(2, 3), 0) return self def test_full_slice(genins): diff --git a/conftest.py b/conftest.py index 867c8e0bf..be08e77e1 100644 --- a/conftest.py +++ b/conftest.py @@ -23,12 +23,16 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("clrd", ["normal_run", "sparse_only_run"], indirect=True) if "genins" in metafunc.fixturenames: metafunc.parametrize("genins", ["normal_run", "sparse_only_run"], indirect=True) + if "prism_convert" in metafunc.fixturenames: + metafunc.parametrize( + "prism_convert", ["normal_run", "sparse_only_run"], indirect=True + ) if "prism_dense" in metafunc.fixturenames: metafunc.parametrize( "prism_dense", ["normal_run", "sparse_only_run"], indirect=True ) if "prism" in metafunc.fixturenames: - metafunc.parametrize("prism", ["normal_run"], indirect=True) + metafunc.parametrize("prism", ["sparse_only_run"], indirect=True) if "xyz" in metafunc.fixturenames: metafunc.parametrize("xyz", ["normal_run", "sparse_only_run"], indirect=True) @@ -56,14 +60,12 @@ def _sample_fixture( """ - # Set the backend to sparse for a sparse-only-run. - cl.options.set_option("ARRAY_BACKEND", "sparse" if request.param == "sparse_only_run" else "numpy") # Load the sample data. tri = cl.load_sample(sample) - # Apply a transformation if supplied, then yield the triangle to the test. - yield transform(tri) if transform else tri - # After the test, reset the backend to default numpy. - cl.options.set_option("ARRAY_BACKEND", "numpy") + # Apply a transformation if supplied + tri = transform(tri) if transform else tri + # Set the backend to sparse for a sparse-only-run, then yield the triangle to the test. + yield tri.set_backend("sparse" if request.param == "sparse_only_run" else "numpy") @pytest.fixture @@ -90,6 +92,9 @@ def genins(request): def prism(request): yield from _sample_fixture(request, "prism") +@pytest.fixture +def prism_convert(request): + yield from _sample_fixture(request, "prism", transform=lambda t: t.iloc[:5000]) @pytest.fixture def prism_dense(request):