Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion chainladder/adjustments/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def fit(self, X, y=None, sample_weight=None):
if self.hat_adj:
try:
self.hat_ = self._get_hat(X, exp_incr_triangle)
except:
except Exception:
warn("Could not compute hat matrix. Setting hat_adj to False")
self.had_adj = False
self.hat_ = None
Expand Down
2 changes: 1 addition & 1 deletion chainladder/adjustments/tests/test_berqsherm.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ def test_adjusted_values():
berq_triangle["Incurred"].values.sum(), 1126985253.661, atol=1e-2
)
assert np.isclose(berq_triangle["Paid"].values.sum(), 182046766.054, atol=1e-2)
assert np.isclose(berq_triangle["Closed"].values.sum(), 8798.982, atol=1e-2)
assert np.isclose(berq_triangle["Closed"].values.sum(), 8798.982, atol=1e-2)
8 changes: 4 additions & 4 deletions chainladder/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,24 +290,24 @@ def _get_date_axes(
end=origin_date.max(),
freq=origin_grain
).to_timestamp(how="s")

development_range: DatetimeIndex = pd.period_range(
start=development_date.min(),
end=development_date.max(),
freq=development_grain,
).to_timestamp(how="e")

# If the development is semi-annual, we need to adjust further because of "2Q-DEC".
if development_grain[:2] == "2Q":
from pandas.tseries.offsets import DateOffset

development_range += DateOffset(months=-3)

c = pd.DataFrame(
TriangleBase._cartesian_product(origin_range, development_range),
columns=["__origin__", "__development__"],
)

return c[c["__development__"] > c["__origin__"]]

@property
Expand Down
2 changes: 1 addition & 1 deletion chainladder/core/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,4 @@ def _dimensionality(self) -> str:
return 'single'

else :
return 'multi'
return 'multi'
22 changes: 11 additions & 11 deletions chainladder/core/dunders.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _compatibility_check(self, x, y):
x, y = set_common_backend([x, y])
if (
x.origin_grain != y.origin_grain
or (x.development_grain != y.development_grain and
or (x.development_grain != y.development_grain and
min(x.shape[-1], y.shape[-1]) > 1)
):
raise ValueError(
Expand Down Expand Up @@ -100,7 +100,7 @@ def _prep_index(self, x, y):
x = x.sort_index()
try:
y = y.loc[x.index]
except:
except Exception:
x = x.groupby(list(common))
y = y.groupby(list(common))
return x, y
Expand All @@ -112,7 +112,7 @@ def _prep_index(self, x, y):

def _prep_columns(self, x, y):
x_backend, y_backend = x.array_backend, y.array_backend

if len(x.columns) == 1 and len(y.columns) > 1:
x.vdims = y.vdims
elif len(y.columns) == 1 and len(x.columns) > 1:
Expand All @@ -121,30 +121,30 @@ def _prep_columns(self, x, y):
y.vdims = x.vdims
elif x.shape[1] == y.shape[1] and np.array_equal(x.columns, y.columns):
return x, y
else:
else:
# Find columns to add to each triangle
cols_to_add_to_x = [col for col in y.columns if col not in x.columns]
cols_to_add_to_y = [col for col in x.columns if col not in y.columns]
cols_to_add_to_x = [col for col in y.columns if col not in x.columns]
cols_to_add_to_y = [col for col in x.columns if col not in y.columns]

# Create new columns only if necessary
if cols_to_add_to_x:
new_x_cols = list(x.columns) + list(cols_to_add_to_x)
x = x.reindex(columns=new_x_cols, fill_value=0)

if cols_to_add_to_y:
new_y_cols = list(y.columns) + list(cols_to_add_to_y)
y = y.reindex(columns=new_y_cols, fill_value=0)

# Ensure both triangles have the same column order
x = x[new_x_cols]
y = y[new_x_cols]

# Reset backends only if they've changed
if x.array_backend != x_backend:
x = x.set_backend(x_backend, inplace=True)
if y.array_backend != y_backend:
y = y.set_backend(y_backend, inplace=True)

return x, y

def _prep_origin_development(self, obj, other):
Expand Down
2 changes: 1 addition & 1 deletion chainladder/core/pandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def to_frame(self, origin_as_datetime=True, keepdims=False,

valuation = pd.DataFrame(
obj.valuation.values.reshape(obj.shape[-2:], order='F'),
index=obj.odims if origin_as_datetime else obj.origin,
index=obj.odims if origin_as_datetime else obj.origin,
columns=obj.ddims
).unstack().rename('valuation').reset_index().rename(
columns={'level_0': 'development', 'level_1': 'origin'})
Expand Down
2 changes: 1 addition & 1 deletion chainladder/core/slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def __setitem__(self, key, value):
self.vdims = self.vdims if key in self.vdims else np.append(self.vdims, key)
try:
self.values = xp.concatenate((self.values, value.values), axis=1)
except:
except Exception:
# For misaligned triangle support
conc = (self.values, (self.iloc[:, 0] * 0 + value).values)
self.values = xp.concatenate(conc, axis=1)
Expand Down
4 changes: 2 additions & 2 deletions chainladder/core/tests/rtest_correlation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### Building out a dev environment with a working copy
### of R ChainLadder is difficult. These tests are
### of R ChainLadder is difficult. These tests are
### Currently inactive, but available should the compatibility
### of the installs improve at a later date.

Expand All @@ -11,7 +11,7 @@
from rpy2.robjects.packages import importr
from rpy2.robjects import r
CL = importr("ChainLadder")
except:
except Exception:
pass

def dev_corr_r(data, ci):
Expand Down
2 changes: 1 addition & 1 deletion chainladder/core/tests/test_correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ def test_dev_corr_sparse():

def test_validate_critical():
with pytest.raises(ValueError):
raa.valuation_correlation(p_critical=1.5, total=True)
raa.valuation_correlation(p_critical=1.5, total=True)
4 changes: 2 additions & 2 deletions chainladder/core/tests/test_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def test_heatmap_render(raa):
try:
raa.heatmap()

except:
except Exception:
assert False


Expand All @@ -24,7 +24,7 @@ def test_to_frame(raa):
cl.Chainladder().fit(raa).ultimate_.to_frame(origin_as_datetime=False)
cl.Chainladder().fit(raa).ultimate_.to_frame(origin_as_datetime=True)

except:
except Exception:
assert False


Expand Down
32 changes: 16 additions & 16 deletions chainladder/core/tests/test_triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

try:
from IPython.core.display import HTML
except:
except Exception:
HTML = None


Expand Down Expand Up @@ -787,17 +787,17 @@ def test_semi_annual_grain():
"2009-01-01", "2009-07-01", "2010-01-01",
"2009-07-01", "2010-01-01",
"2010-01-01"],
'loss': [100, 200, 300, 400, 500, 600, 700,
150, 300, 450, 500, 550, 600,
200, 250, 350, 400, 450,
'loss': [100, 200, 300, 400, 500, 600, 700,
150, 300, 450, 500, 550, 600,
200, 250, 350, 400, 450,
50, 100, 150, 200,
100, 200, 300,
50, 150,
50, 150,
100]
}

Stri = cl.Triangle(
pd.DataFrame(Sdata),
pd.DataFrame(Sdata),
origin='origin',
development='development',
columns='loss',
Expand All @@ -813,14 +813,14 @@ def test_semi_annual_grain():
"2008-01-01", "2009-01-01", "2010-01-01",
"2009-01-01", "2010-01-01",
"2010-01-01"],
'loss': [100, 600, 1000, 1300,
200, 450, 650,
'loss': [100, 600, 1000, 1300,
200, 450, 650,
100, 450,
100]
}

Atri = cl.Triangle(
pd.DataFrame(Adata),
pd.DataFrame(Adata),
origin='origin',
development='development',
columns='loss',
Expand All @@ -833,7 +833,7 @@ def test_odd_quarter_end():
["5/1/2023", 12, '4/30/2024', 100],
["8/1/2023", 9, "4/30/2024", 130],
["11/1/2023", 6, "4/30/2024", 160],
["2/1/2024", 3, "4/30/2024", 140]],
["2/1/2024", 3, "4/30/2024", 140]],
columns = ['origin', 'development', 'valuation', 'EarnedPremium'])
triangle = cl.Triangle(
data, origin='origin', origin_format='%Y-%m-%d', development='valuation', columns='EarnedPremium', trailing=True, cumulative=True
Expand Down Expand Up @@ -867,7 +867,7 @@ def test_single_valuation_date_preserves_exact_date():
assert triangle.development_grain == 'M'
assert int(triangle.valuation_date.strftime('%Y%m')) == 202510
def test_OXDX_triangle():

for x in [12,6,3,1]:
for y in [i for i in [12,6,3,1] if i <= x]:
first_orig = '2020-01-01'
Expand All @@ -881,13 +881,13 @@ def test_OXDX_triangle():
for i in range(12):
for j in range(y):
test_data = tri_df.copy()
test_data['origin_date'] += pd.DateOffset(months=i)
test_data['origin_date'] += pd.DateOffset(months=i)
test_data['development_date'] += pd.DateOffset(months=i-j)
tri = cl.Triangle(
test_data,
origin='origin_date',
development='development_date',
columns='value',
test_data,
origin='origin_date',
development='development_date',
columns='value',
cumulative=True
)
assert tri.shape == (1,1,2,width)
Expand Down
14 changes: 7 additions & 7 deletions chainladder/core/triangle.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def __init__(
# Store dimension metadata.
self.columns_label: list = columns
self.origin_label: list = origin

# Handle any ultimate vectors in triangles separately.
data, ult = self._split_ult(
data=data,
Expand Down Expand Up @@ -195,11 +195,11 @@ def __init__(
# Ensure that origin_date values represent the beginning of the period.
# i.e., 1990 means the start of 1990.
origin_date: Series = to_period(origin_date,self.origin_grain).dt.to_timestamp(how="s")

# Ensure that development_date values represent the end of the period.
# i.e., 1990 means the end of 1990 assuming annual development periods.
development_date: Series = to_period(development_date,self.development_grain).dt.to_timestamp(how="e")

# Aggregate dates to the origin/development grains.
data_agg: DataFrame = self._aggregate_data(
data=data,
Expand All @@ -208,7 +208,7 @@ def __init__(
index=index,
columns=columns,
)

# Fill in missing periods with zeros.
date_axes: DataFrame = self._get_date_axes(
data_agg["__origin__"],
Expand Down Expand Up @@ -253,7 +253,7 @@ def __init__(
self.is_cumulative: bool = cumulative
self.virtual_columns = VirtualColumns(self)
self.is_pattern: bool = pattern

split: list[str] = self.origin_grain.split("-")
self.origin_grain: str = {"A": "Y", "2Q": "S"}.get(split[0], split[0])

Expand Down Expand Up @@ -831,7 +831,7 @@ def grain(self, grain="", trailing=False, inplace=False):
addl.ddims = addl_ts
obj = concat((addl, obj), axis=-1)
obj.values = num_to_nan(obj.values)

if dgrain_old != dgrain_new and obj.shape[-1] > 1:
step = self._dstep()[dgrain_old][dgrain_new]
d = np.sort(
Expand All @@ -847,7 +847,7 @@ def grain(self, grain="", trailing=False, inplace=False):
obj.ddims = ddims

obj.development_grain = dgrain_new

obj = obj.dev_to_val() if self.is_val_tri else obj.val_to_dev()

if inplace:
Expand Down
6 changes: 3 additions & 3 deletions chainladder/development/incremental.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def fit(self, X, y=None, sample_weight=None):
self.sample_weight = sample_weight
self.fit_zeta_ = self.tri_zeta * self.w_
self.zeta_ = self._param_property(x,self.params_.slope_[...,0][..., None, :])

#to consolidate under full_triangle_
y_ = xp.repeat(self.zeta_.values, len(x.odims), -2)
obj = x.copy()
Expand All @@ -170,7 +170,7 @@ def fit(self, X, y=None, sample_weight=None):
self.incremental_ = self.incremental_.trend(
1/(1+future_trend)-1, axis='valuation', start=X.valuation_date,
end=self.incremental_.valuation_date)

#to migrate under _zeta_to_ldf method under common, so ldf_ can be correct after tail
self.ldf_ = obj.incr_to_cum().link_ratio
return self
Expand All @@ -195,7 +195,7 @@ def transform(self, X):

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
Expand Down
8 changes: 4 additions & 4 deletions chainladder/development/learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ def _prep_X_ml(self, X):

def _prep_w_ml(self,X,sample_weight=None):
weight_base = (~np.isnan(X.values)).astype(float)
weight = weight_base.copy()
weight = weight_base.copy()
if self.drop is not None:
weight = weight * self._drop_func(X)
if self.drop_valuation is not None:
weight = weight * self._drop_valuation_func(X)
if sample_weight is not None:
weight = weight * sample_weight.values
weight = weight * sample_weight.values
return weight.flatten()[weight_base.flatten()>0]

def fit(self, X, y=None, sample_weight=None):
Expand Down Expand Up @@ -206,7 +206,7 @@ def fit(self, X, y=None, sample_weight=None):
sample_weights = {self.weighted_step + '__sample_weight':weight}
# Fit model
self.estimator_ml.fit(df, self.y_ml_.fit_transform(df).squeeze(),**sample_weights)
#return selffit_incrementals
#return selffit_incrementals
self.triangle_ml_, self.predicted_data_ = self._get_triangle_ml(df)
return self

Expand Down Expand Up @@ -238,4 +238,4 @@ def transform(self, X):
X_new.ldf_.valuation_date = pd.to_datetime(options.ULT_VAL)
X_new._set_slicers()
X_new.predicted_data_ = predicted_data
return X_new
return X_new
4 changes: 2 additions & 2 deletions chainladder/development/tests/rtest_clark.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### Building out a dev environment with a working copy
### of R ChainLadder is difficult. These tests are
### of R ChainLadder is difficult. These tests are
### Currently inactive, but available should the compatibility
### of the installs improve at a later date.

Expand All @@ -11,7 +11,7 @@
from rpy2.robjects.packages import importr
from rpy2.robjects import r
CL = importr("ChainLadder")
except:
except Exception:
pass

@pytest.mark.r
Expand Down
Loading