diff --git a/chainladder/adjustments/bootstrap.py b/chainladder/adjustments/bootstrap.py index 101b84dd..a2592971 100644 --- a/chainladder/adjustments/bootstrap.py +++ b/chainladder/adjustments/bootstrap.py @@ -344,7 +344,8 @@ def _get_hetero_adjustment(self): pass def transform(self, X): - """If X and self are of different shapes, align self to X, else + """ + If X and self are of different shapes, align self to X, else return self. Parameters diff --git a/chainladder/adjustments/disposal.py b/chainladder/adjustments/disposal.py index 71d1c1eb..fcd3a568 100644 --- a/chainladder/adjustments/disposal.py +++ b/chainladder/adjustments/disposal.py @@ -285,7 +285,8 @@ def fit(self, X: Triangle, y: None = None, sample_weight: Triangle | None = None return self def transform(self, X: Triangle, sample_weight: Triangle | None = None) -> Triangle: - """If X and self are of different shapes, align self to X, else + """ + If X and self are of different shapes, align self to X, else return self. Parameters @@ -318,7 +319,8 @@ def transform(self, X: Triangle, sample_weight: Triangle | None = None) -> Trian return X_new def fit_transform(self, X, y=None, sample_weight=None): - """Fit and return transformed full_triangle_ based on the Disposal Rate + """ + Fit and return transformed full_triangle_ based on the Disposal Rate Parameters ---------- diff --git a/chainladder/adjustments/parallelogram.py b/chainladder/adjustments/parallelogram.py index 91545714..09a85f09 100644 --- a/chainladder/adjustments/parallelogram.py +++ b/chainladder/adjustments/parallelogram.py @@ -262,7 +262,8 @@ def __init__( self.cumulative = cumulative def fit(self, X, y=None, sample_weight=None): - """Fit the model with X. + """ + Fit the model with X. Parameters ---------- @@ -332,7 +333,8 @@ def _combine_duplicate_dates(self, r): return (r.groupby(self.date_col)[self.change_col].prod() - 1).reset_index() def transform(self, X, y=None, sample_weight=None): - """If X and self are of different shapes, align self to X, else + """ + If X and self are of different shapes, align self to X, else return self. Parameters diff --git a/chainladder/adjustments/tests/test_parallelogram.py b/chainladder/adjustments/tests/test_parallelogram.py index 8a8c4310..9e74c461 100644 --- a/chainladder/adjustments/tests/test_parallelogram.py +++ b/chainladder/adjustments/tests/test_parallelogram.py @@ -457,7 +457,8 @@ def test_cumulative_rejects_non_positive(): def test_cumulative_factor_predates_window(): - """A factor in force before the triangle window is honored, not dropped. + """ + A factor in force before the triangle window is honored, not dropped. The earliest factor's effective date (2000) predates the triangle's lookback window (origins start 2003), so it must still apply to the first diff --git a/chainladder/adjustments/trend.py b/chainladder/adjustments/trend.py index 610b5228..425b0f47 100644 --- a/chainladder/adjustments/trend.py +++ b/chainladder/adjustments/trend.py @@ -163,7 +163,8 @@ def __init__(self, trends=0.0, dates=None, axis="origin"): self.axis = axis def fit(self, X, y=None, sample_weight=None): - """Fit the model with X. + """ + Fit the model with X. Parameters ---------- @@ -193,7 +194,8 @@ def fit(self, X, y=None, sample_weight=None): return self def transform(self, X, y=None, sample_weight=None): - """If X and self are of different shapes, align self to X, else + """ + If X and self are of different shapes, align self to X, else return self. Parameters diff --git a/chainladder/core/base.py b/chainladder/core/base.py index b86100af..ac89fc13 100644 --- a/chainladder/core/base.py +++ b/chainladder/core/base.py @@ -55,7 +55,8 @@ class TriangleBase( @property def shape(self): - """The 4-D shape of the Triangle: ``(index, columns, origin, development)``. + """ + The 4-D shape of the Triangle: ``(index, columns, origin, development)``. Examples -------- @@ -79,7 +80,8 @@ def shape(self): @property def dimensionality(self): - """The dimensionality of the Triangle. + """ + The dimensionality of the Triangle. Returns ``'empty'`` for a Triangle instantiated without data (e.g. ``cl.Triangle()``), ``'single'`` for a Triangle holding a @@ -107,7 +109,8 @@ def dimensionality(self): @property def empty(self): - """Whether the Triangle contains any data. + """ + Whether the Triangle contains any data. Mirrors ``pandas.DataFrame.empty``. Returns ``True`` for a Triangle instantiated without data (e.g. ``cl.Triangle()``), whose ``values`` @@ -425,7 +428,8 @@ def is_ultimate(self) -> bool: @property def nan_triangle(self): - """Given the current triangle shape and valuation, it determines the + """ + Given the current triangle shape and valuation, it determines the appropriate placement of NANs in the triangle for future valuations. This becomes useful when managing array arithmetic. @@ -775,7 +779,8 @@ def __array_function__(self, func, types, args, kwargs): return HANDLED_FUNCTIONS[func](*args, **kwargs) def compute(self, *args, **kwargs): - """Materialize a lazy dask-backed Triangle. + """ + Materialize a lazy dask-backed Triangle. When ``values`` is a dask array, compute it and update ``array_backend`` to match the resulting array type. Returns ``self`` @@ -819,7 +824,8 @@ def _get_axis_value(self, axis): def is_chainladder(estimator): - """Return True if the given estimator is a chainladder based method. + """ + Return True if the given estimator is a chainladder based method. Parameters ---------- estimator : object diff --git a/chainladder/core/common.py b/chainladder/core/common.py index dd949553..8f421cb5 100644 --- a/chainladder/core/common.py +++ b/chainladder/core/common.py @@ -89,7 +89,8 @@ def has_zeta(self): @property def cdf_(self): - """Cumulative development factors, ``ldf_`` converted with ``incr_to_cum``. + """ + Cumulative development factors, ``ldf_`` converted with ``incr_to_cum``. Examples -------- @@ -117,7 +118,8 @@ def cdf_(self): @property def pct_reported_(self): - """Percentage of ultimate reported (or paid) at each development age, + """ + Percentage of ultimate reported (or paid) at each development age, equal to the inverse of the cumulative development factor. Examples @@ -146,8 +148,10 @@ def pct_reported_(self): @property def pct_unreported_(self): - """Percentage of ultimate still unreported (or unpaid) at each - development age, equal to ``1 - 1 / cdf_``.""" + """ + Percentage of ultimate still unreported (or unpaid) at each + development age, equal to ``1 - 1 / cdf_``. + """ if not self.has_ldf: x = self.__class__.__name__ raise AttributeError( @@ -164,7 +168,8 @@ def cum_zeta_(self): @property def ibnr_(self): - """Outstanding development to ultimate: ``ultimate_`` minus the latest + """ + Outstanding development to ultimate: ``ultimate_`` minus the latest diagonal (or the origin total, for incremental triangles). Examples @@ -227,7 +232,8 @@ def full_triangle_(self): return _get_full_triangle(X, self.ultimate_, X.is_cumulative) def pipe(self, func, *args, **kwargs): - """Apply ``func(self, *args, **kwargs)``. + """ + Apply ``func(self, *args, **kwargs)``. Parameters ---------- diff --git a/chainladder/core/dunders.py b/chainladder/core/dunders.py index 875b68e8..0d00a090 100644 --- a/chainladder/core/dunders.py +++ b/chainladder/core/dunders.py @@ -24,8 +24,8 @@ class TriangleDunders: - """Class that implements the dunder (double underscore) methods for the - Triangle class + """ + Class that implements the dunder (double underscore) methods for the Triangle class """ def _validate_arithmetic(self, other: Any) -> tuple: @@ -263,7 +263,12 @@ def _slice_or_nan(obj, other, k): @staticmethod def _get_key_union(obj, other): - return set(list(obj.groups.indices.keys()) + list(other.groups.indices.keys())) + # fmt: off + return set( + list(obj.groups.indices.keys()) + + list(other.groups.indices.keys()) + ) + # fmt: on def _arithmetic_mapper(self, obj, other, f): """Use Dask if available, otherwise basic list comprehension""" @@ -277,7 +282,8 @@ def _arithmetic_mapper(self, obj, other, f): return concat(c, 0).sort_index() def __add__(self, other): - """Element-wise addition. + """ + Element-wise addition. Examples -------- @@ -313,9 +319,10 @@ def __add__(self, other): if isinstance(obj, TriangleGroupBy): def f(k, self, obj, other): - return self._slice_or_nan(obj, other, k) + self._slice_or_nan( - other, obj, k - ) + # fmt: off + return (self._slice_or_nan(obj, other, k) + + self._slice_or_nan(other, obj, k)) + # fmt: on obj = self._arithmetic_mapper(obj, other, f) else: @@ -327,7 +334,8 @@ def __radd__(self, other): return self if other == 0 else self.__add__(other) def __sub__(self, other): - """Element-wise subtraction. + """ + Element-wise subtraction. Examples -------- @@ -361,9 +369,10 @@ def __sub__(self, other): if isinstance(obj, TriangleGroupBy): def f(k, self, obj, other): - return self._slice_or_nan(obj, other, k) - self._slice_or_nan( - other, obj, k - ) + # fmt: off + return (self._slice_or_nan(obj, other, k) - + self._slice_or_nan(other, obj, k)) + # fmt: on obj = self._arithmetic_mapper(obj, other, f) else: @@ -404,7 +413,8 @@ def __abs__(self): return obj def __mul__(self, other): - """Element-wise multiplication. + """ + Element-wise multiplication. Examples -------- @@ -438,9 +448,10 @@ def __mul__(self, other): if isinstance(obj, TriangleGroupBy): def f(k, self, obj, other): - return self._slice_or_nan(obj, other, k) * self._slice_or_nan( - other, obj, k - ) + # fmt: off + return (self._slice_or_nan(obj, other, k) * + self._slice_or_nan(other, obj, k)) + # fmt: on obj = self._arithmetic_mapper(obj, other, f) else: @@ -455,9 +466,10 @@ def __pow__(self, other): if isinstance(obj, TriangleGroupBy): def f(k, self, obj, other): - return self._slice_or_nan(obj, other, k) ** self._slice_or_nan( - other, obj, k - ) + # fmt: off + return (self._slice_or_nan(obj, other, k) ** + self._slice_or_nan(other, obj, k)) + # fmt: on obj = self._arithmetic_mapper(obj, other, f) else: @@ -528,9 +540,10 @@ def __truediv__(self, other: Any): if isinstance(obj, TriangleGroupBy): def f(k, self, obj, other): - return self._slice_or_nan(obj, other, k) / self._slice_or_nan( - other, obj, k - ) + # fmt: off + return (self._slice_or_nan(obj, other, k) / + self._slice_or_nan(other, obj, k)) + # fmt: on obj = self._arithmetic_mapper(obj, other, f) else: diff --git a/chainladder/core/io.py b/chainladder/core/io.py index 6f6836a6..c41d7f16 100644 --- a/chainladder/core/io.py +++ b/chainladder/core/io.py @@ -1,6 +1,7 @@ """ 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/. @@ -13,7 +14,8 @@ class TriangleIO: def to_pickle(self, path, protocol=None): - """ Serializes triangle object to pickle. + """ + Serializes triangle object to pickle. Parameters ---------- @@ -53,7 +55,8 @@ def to_pickle(self, path, protocol=None): dill.dump(self, pkl) def to_json(self): - """ Serializes triangle object to json format + """ + Serializes triangle object to json format Returns ------- @@ -88,8 +91,13 @@ def to_json(self): "is_pattern": self.is_pattern, "columns": list(self.columns), } - out = self.cum_to_incr().dev_to_val().to_frame( - keepdims=True, origin_as_datetime=True).fillna(0) + out = ( + self + .cum_to_incr() + .dev_to_val() + .to_frame(keepdims=True, origin_as_datetime=True) + .fillna(0) + ) x = out.reset_index().to_json(orient="split", date_unit="ns") json_dict = {"metadata": json.dumps(metadata), "data": x} sub_tris = [k for k, v in vars(self).items() if isinstance(v, TriangleIO)] @@ -99,17 +107,18 @@ def to_json(self): dfs = [k for k, v in vars(self).items() if isinstance(v, pd.DataFrame)] json_dict["dfs"] = {df: getattr(self, df).to_json() for df in dfs} dfs = [k for k, v in vars(self).items() if isinstance(v, pd.Series)] - json_dict["dfs"].update( - {df: getattr(self, df).to_frame().to_json() for df in dfs} - ) + json_dict["dfs"].update({ + df: getattr(self, df).to_frame().to_json() for df in dfs + }) return json.dumps(json_dict) class EstimatorIO: - """ Class intended to allow persistence of estimator objects """ + """Class intended to allow persistence of estimator objects""" def to_pickle(self, path, protocol=None): - """ Serializes triangle object to pickle. + """ + Serializes triangle object to pickle. Parameters ---------- @@ -149,7 +158,8 @@ def to_pickle(self, path, protocol=None): dill.dump(self, pkl) def to_json(self): - """ Serializes triangle object to json format + """ + Serializes triangle object to json format Returns ------- diff --git a/chainladder/core/pandas.py b/chainladder/core/pandas.py index 4b7237ba..5d0a8508 100644 --- a/chainladder/core/pandas.py +++ b/chainladder/core/pandas.py @@ -70,7 +70,8 @@ def to_frame( keepdims: bool = False, implicit_axis: bool = False, ) -> DataFrame | Series: - """Converts a triangle to a pandas.DataFrame. + """ + Converts a triangle to a pandas.DataFrame. Parameters ---------- @@ -531,7 +532,8 @@ def dropna(self) -> Triangle: return obj def fillna(self, value: int | float | ndarray, inplace: bool = False) -> Triangle: - """Fill nan with 'value' by axis. + """ + Fill nan with 'value' by axis. Parameters ---------- @@ -563,7 +565,8 @@ def fillna(self, value: int | float | ndarray, inplace: bool = False) -> Triangl return new_obj def fillzero(self, inplace: bool = False) -> Triangle: - """Fill nan with 0 by axis. separate function from fillna() because fillna(0) isn't working. + """ + Fill nan with 0 by axis. separate function from fillna() because fillna(0) isn't working. Parameters ---------- @@ -590,7 +593,8 @@ def fillzero(self, inplace: bool = False) -> Triangle: return new_obj def ffill(self, axis: int | str = 3) -> Triangle: - """Forward-fill missing values along an axis. + """ + Forward-fill missing values along an axis. Only cells within the observed triangle (see ``nan_triangle``) are filled; a cell that has not yet been valued is left as-is regardless @@ -703,7 +707,8 @@ def _validate_contiguous_drop( axis_name: str, errors: str, ) -> np.ndarray: - """Validate and return boolean keep mask for dropping contiguous edge periods. + """ + Validate and return boolean keep mask for dropping contiguous edge periods. Parameters ---------- @@ -749,7 +754,8 @@ def drop( level: int | str | None = None, errors: str = "raise", ) -> Triangle: - """Drop specified labels from rows or columns. + """ + Drop specified labels from rows or columns. Remove labels by specifying label names and corresponding axis, or by specifying directly ``index``, ``columns``, ``origin``, or @@ -1008,7 +1014,8 @@ def rename( axis: Literal["index", "columns", "origin", "development"] | int, value: str | list | dict, ) -> Triangle: - """Alter Triangle axes labels. + """ + Alter Triangle axes labels. Parameters ---------- @@ -1052,7 +1059,8 @@ def rename( return cast("Triangle", cast(object, self)) def astype(self, dtype, inplace=True) -> Triangle: - """Copy of the array, cast to a specified type. + """ + Copy of the array, cast to a specified type. Parameters ---------- @@ -1070,7 +1078,8 @@ def astype(self, dtype, inplace=True) -> Triangle: return cast("Triangle", obj) def head(self, n: int = 5) -> Triangle: - """Return the first ``n`` triangles along the index axis. + """ + Return the first ``n`` triangles along the index axis. Parameters ---------- @@ -1084,7 +1093,8 @@ def head(self, n: int = 5) -> Triangle: return self.iloc[:n] def tail(self, n: int = 5) -> Triangle: - """Return the last ``n`` triangles along the index axis. + """ + Return the last ``n`` triangles along the index axis. Parameters ---------- @@ -1098,7 +1108,8 @@ def tail(self, n: int = 5) -> Triangle: return self.iloc[-n:] def sort_index(self, *args, **kwargs) -> Triangle: - """Sort Triangle rows by index labels. + """ + Sort Triangle rows by index labels. Returns ------- @@ -1110,7 +1121,8 @@ def sort_index(self, *args, **kwargs) -> Triangle: return self.iloc[sorted_index.index] def exp(self) -> Triangle: - """Return the exponential of each element. + """ + Return the exponential of each element. Returns ------- @@ -1119,7 +1131,8 @@ def exp(self) -> Triangle: return self.get_array_module().exp(self) def log(self) -> Triangle: - """Return the natural logarithm of each element. + """ + Return the natural logarithm of each element. Returns ------- @@ -1128,7 +1141,8 @@ def log(self) -> Triangle: return self.get_array_module().log(self) def minimum(self, other: Triangle | int | float) -> Triangle: - """Element-wise minimum of this Triangle and another operand. + """ + Element-wise minimum of this Triangle and another operand. See :func:`chainladder.minimum` for parameters, usage, and examples. @@ -1136,14 +1150,16 @@ def minimum(self, other: Triangle | int | float) -> Triangle: return self.get_array_module().minimum(self, other) def maximum(self, other: Triangle | int | float) -> Triangle: - """Element-wise maximum of this Triangle and another operand. + """ + Element-wise maximum of this Triangle and another operand. See :func:`chainladder.maximum` for parameters, usage, and examples. """ return self.get_array_module().maximum(self, other) def sqrt(self) -> Triangle: - """Return the non-negative square root of each element. + """ + Return the non-negative square root of each element. Returns ------- @@ -1152,7 +1168,8 @@ def sqrt(self) -> Triangle: return self.get_array_module().sqrt(self) def round(self, decimals: int = 0) -> Triangle: - """Round each element to the given number of decimal places. + """ + Round each element to the given number of decimal places. Uses banker's rounding (round half to even). For example, ``(8.5).round(0)`` returns 8, not 9. For conventional rounding, diff --git a/pyproject.toml b/pyproject.toml index b5edad14..ac16743f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,6 +108,7 @@ extend-exclude = ["docs/getting_started/online_sandbox/sandbox_workbook_blank.ip select = [ "B018", "BLE001", + "D213", "E2", "E4", "E7",