Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions chainladder/core/dunders.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
x = x.sort_index()
try:
y = y.loc[x.index]
except:

Check failure on line 104 in chainladder/core/dunders.py

View workflow job for this annotation

GitHub Actions / ruff check

ruff (E722)

chainladder/core/dunders.py:104:17: E722 Do not use bare `except`
x = x.groupby(list(common))
y = y.groupby(list(common))
return x, y
Expand Down Expand Up @@ -206,7 +206,7 @@
other_arr.shape = (other.shape[0], other.shape[1], len(odims), len(ddims))
obj_arr.shape = (self.shape[0], self.shape[1], len(odims), len(ddims))
obj.odims = np.array(odims.index)
if type(obj.ddims) == pd.DatetimeIndex:

Check failure on line 209 in chainladder/core/dunders.py

View workflow job for this annotation

GitHub Actions / ruff check

ruff (E721)

chainladder/core/dunders.py:209:16: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
obj.ddims = pd.DatetimeIndex(ddims.index)
else:
obj.ddims = np.array(ddims.index)
Expand Down Expand Up @@ -247,6 +247,37 @@
return concat(c, 0).sort_index()

def __add__(self, other):
"""Element-wise addition.

Examples
--------
Adding a scalar shifts every observed cell.

.. testsetup::

import chainladder as cl
tri = cl.Triangle(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should tri be in testcode instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved. testsetup is only import chainladder as cl; the Triangle is built in testcode.

data={
'origin': [1985, 1985, 1986],
'development': [1985, 1986, 1986],
'paid': [100, 150, 80],
},
origin='origin',
development='development',
columns=['paid'],
cumulative=True,
)

.. testcode::

print(tri + 10)

.. testoutput::

12 24
1985 110.0 160.0
1986 90.0 NaN
"""
obj, other = self._validate_arithmetic(other)
if isinstance(obj, TriangleGroupBy):
def f(k, self, obj, other):
Expand All @@ -262,6 +293,35 @@
return self if other == 0 else self.__add__(other)

def __sub__(self, other):
"""Element-wise subtraction.

Examples
--------
.. testsetup::

import chainladder as cl
tri = cl.Triangle(
data={
'origin': [1985, 1985, 1986],
'development': [1985, 1986, 1986],
'paid': [100, 150, 80],
},
origin='origin',
development='development',
columns=['paid'],
cumulative=True,
)

.. testcode::

print(tri - 10)

.. testoutput::

12 24
1985 90.0 140.0
1986 70.0 NaN
"""
obj, other = self._validate_arithmetic(other)
if isinstance(obj, TriangleGroupBy):
def f(k, self, obj, other):
Expand Down Expand Up @@ -306,6 +366,35 @@
return obj

def __mul__(self, other):
"""Element-wise multiplication.

Examples
--------
.. testsetup::

import chainladder as cl
tri = cl.Triangle(
data={
'origin': [1985, 1985, 1986],
'development': [1985, 1986, 1986],
'paid': [100, 150, 80],
},
origin='origin',
development='development',
columns=['paid'],
cumulative=True,
)

.. testcode::

print(tri * 2)

.. testoutput::

12 24
1985 200.0 300.0
1986 160.0 NaN
"""
obj, other = self._validate_arithmetic(other)
if isinstance(obj, TriangleGroupBy):
def f(k, self, obj, other):
Expand All @@ -313,7 +402,7 @@
self._slice_or_nan(other, obj, k))
obj = self._arithmetic_mapper(obj, other, f)
else:
xp = obj.get_array_module()

Check failure on line 405 in chainladder/core/dunders.py

View workflow job for this annotation

GitHub Actions / ruff check

ruff (F841)

chainladder/core/dunders.py:405:13: F841 Local variable `xp` is assigned to but never used help: Remove assignment to unused variable `xp`
obj.values = obj.values * other
return obj

Expand Down Expand Up @@ -347,6 +436,47 @@

other: Any
The thing that divides the triangle.

Examples
--------
Dividing by a scalar scales the triangle. Dividing two columns is the
usual way to form a ratio triangle, such as paid-to-incurred.

.. testsetup::

import chainladder as cl
tri = cl.Triangle(
data={
'origin': [1985, 1985, 1986],
'development': [1985, 1986, 1986],
'paid': [100, 150, 80],
'incurred': [120, 160, 100],
},
origin='origin',
development='development',
columns=['paid', 'incurred'],
cumulative=True,
)

.. testcode::

print(tri['paid'] / 2)

.. testoutput::

12 24
1985 50.0 75.0
1986 40.0 NaN

.. testcode::

print(tri['paid'] / tri['incurred'])

.. testoutput::

12 24
1985 0.833333 0.9375
1986 0.800000 NaN
"""
obj, other = self._validate_arithmetic(other)
if isinstance(obj, TriangleGroupBy):
Expand Down
1 change: 1 addition & 0 deletions docs/_templates/autosummary/class_inherited.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
:members:
:inherited-members:
:undoc-members:
:special-members: __add__, __sub__, __mul__, __truediv__
:exclude-members: set_fit_request, set_predict_request, set_score_request, set_transform_request, {{ attributes | join(', ') }}
Loading