Skip to content
11 changes: 7 additions & 4 deletions chainladder/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
from typing import Optional, TYPE_CHECKING

if TYPE_CHECKING:
from chainladder import Triangle
from pandas import DataFrame, Series
from numpy.typing import ArrayLike
from pandas.core.indexes.datetimes import DatetimeIndex
Expand Down Expand Up @@ -666,12 +665,16 @@ def get_array_module(
+ ", ".join([*modules])
) from e

def _auto_sparse(self) -> Triangle:
def _auto_sparse(self) -> None:
"""
Auto sparsifies at 30Mb or more and 20% density or less.

Returns
-------
None
"""
if not options.AUTO_SPARSE:
return self
return None
n = np.prod(list(self.shape) + [8 / 1e6])
if (
self.array_backend == "numpy"
Expand All @@ -683,7 +686,7 @@ def _auto_sparse(self) -> Triangle:
self.values.density < 0.2 and n > 30
):
self.set_backend("numpy", inplace=True)
return self
return None

@property
def valuation(self):
Expand Down
4 changes: 2 additions & 2 deletions chainladder/core/pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ def agg_func(
)
obj._set_slicers()
if auto_sparse:
obj = obj._auto_sparse()
obj._auto_sparse()
obj.values = cast("BackendArray", num_to_nan(obj.values))
if not keepdims and obj.shape == (1, 1, 1, 1):
return obj.values[0, 0, 0, 0]
Expand Down Expand Up @@ -1380,7 +1380,7 @@ def aggregate(i, obj, axis, v):
obj.odims = odims.values
obj._set_slicers()
if auto_sparse:
obj = obj._auto_sparse()
obj._auto_sparse()
return obj

set_method(cls=cls, func=agg_func, k=k)
Expand Down
17 changes: 14 additions & 3 deletions chainladder/core/tests/test_grain.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,19 @@
from chainladder import Triangle


def test_grain(qtr):
# this test is dense only in practice, since grain() applies auto_sparse, which is True by default
def test_grain(qtr: Triangle) -> None:
"""
Tests quarterly to annual grain conversion

Parameters
----------
qtr : Triangle
The qtr sample dataset Triangle.

Returns
-------
None
"""
actual = qtr.iloc[0, 0].grain("OYDY")
nan = np.nan
expected = np.array([
Expand All @@ -28,7 +39,7 @@ def test_grain(qtr):
[21, 422, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
[13, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
])
np.testing.assert_array_equal(actual.values[0, 0, :, :], expected)
np.testing.assert_array_equal(actual.to_frame().values, expected)


def test_grain_returns_valid_tri(qtr):
Expand Down
65 changes: 53 additions & 12 deletions chainladder/core/tests/test_triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,9 @@ def test_dev_to_val_inplace_on_val_tri_returns_self(qtr: Triangle) -> None:
"""
val_tri = qtr.dev_to_val()
assert val_tri.is_val_tri

result = val_tri.dev_to_val(inplace=True)

assert result is val_tri
new_val_tri = val_tri.copy()
new_val_tri.dev_to_val(inplace=True)
assert new_val_tri == val_tri


def test_valdev2(qtr):
Expand All @@ -491,8 +490,25 @@ def test_valdev3(qtr):


def test_valdev4(raa: Triangle) -> None:
lhs = raa.dev_to_val()[raa.dev_to_val().development >= "1989"].values.flatten()
rhs = raa[raa.valuation >= "1989"].dev_to_val().values.flatten()
"""
Tests slicing using the development axis of a valuation Triangle

Parameters
----------
raa : Triangle
The raa sample dataset Triangle.

Returns
-------
None
"""
lhs = (
raa
.dev_to_val()[raa.dev_to_val().development >= "1989"]
.to_frame()
.values.flatten()
)
rhs = raa[raa.valuation >= "1989"].dev_to_val().to_frame().values.flatten()
np.testing.assert_array_equal(lhs[~np.isnan(lhs)], rhs[~np.isnan(rhs)])


Expand Down Expand Up @@ -1011,8 +1027,8 @@ def test_auto_sparse_disabled_returns_self(prism: Triangle) -> None:
dense = small_prism.set_backend("numpy")
cl.options.set_option("AUTO_SPARSE", False)
try:
result = dense._auto_sparse()
assert result is dense
result = dense.copy()
result._auto_sparse()
Comment thread
cursor[bot] marked this conversation as resolved.
assert result.array_backend == "numpy"
finally:
cl.options.reset_option("AUTO_SPARSE")
Expand Down Expand Up @@ -1165,9 +1181,9 @@ def test_auto_sparse_converts_numpy_to_sparse(prism: Triangle) -> None:
dense = small_prism.set_backend("numpy")
assert dense.array_backend == "numpy"

result = dense._auto_sparse()
result = dense.copy()
result._auto_sparse()

assert result is dense
assert result.array_backend == "sparse"


Expand Down Expand Up @@ -3433,7 +3449,7 @@ def test_feed_age_into_valuation_raises() -> None:

def test_fill(clrd: Triangle) -> None:
"""
``Fill`` method works as intended
``fill`` method works as intended
"""
fill_tri = clrd.iloc[2:4, 4:6].fill(100)
# (10 + 1) * 10 / 2 is the number of valid values in one single triangle
Expand All @@ -3445,8 +3461,33 @@ def test_fill(clrd: Triangle) -> None:

def test_full_fill(raa: Triangle) -> None:
"""
``Fill`` method works as intended on full triangle
``fill`` method works as intended on full triangle
"""
full_tri = cl.Chainladder().fit(raa).full_triangle_
fill_full_tri = full_tri.fill(200)
assert np.all(fill_full_tri.values == np.broadcast_to([200], (1, 1, 10, 12)))


def test_dev_val_inplace(raa: Triangle) -> None:
"""
``dev_to_val`` and ``val_to_dev`` methods respect ``inplace``

Parameters
----------
raa : Triangle
The raa sample data set.

Returns
-------
None
"""
raa_copy = raa.copy()
raa_copy2 = raa.copy()
assert raa_copy2.dev_to_val(True) is None
assert raa_copy == raa
assert raa_copy2 == raa_copy.dev_to_val()
raa_copy = raa.copy().dev_to_val()
raa_copy2 = raa_copy.copy()
assert raa_copy2.val_to_dev(True) is None
assert raa_copy2 == raa
assert raa_copy == raa_copy2.dev_to_val()
Loading
Loading