├── docs ├── readme.rst ├── modules.rst ├── index.rst ├── Makefile ├── _templates │ ├── custom-class-template.rst │ └── custom-module-template.rst ├── make.bat └── conf.py ├── tests ├── test_ensemble │ ├── ia_sample_compile_true_t.npy │ ├── ia_sample_compile_true_actual.npy │ └── ia_sample_compile_true_expected.npy ├── test_score.py ├── test_split.py ├── test_datasets.py ├── test_methods.py └── test_ensemble.py ├── src └── tryangle │ ├── utils │ ├── __init__.py │ ├── datasets.py │ └── data │ │ ├── swiss_train.csv │ │ ├── cas_test.csv │ │ ├── sme_test.csv │ │ ├── swiss_test.csv │ │ ├── cas_train.csv │ │ └── sme_train.csv │ ├── __init__.py │ ├── model_selection │ ├── __init__.py │ └── split.py │ ├── metrics │ ├── __init__.py │ ├── base.py │ └── score.py │ ├── core │ ├── __init__.py │ ├── base.py │ └── methods.py │ └── ensemble │ ├── __init__.py │ ├── losses.py │ ├── optimizers.py │ └── base.py ├── tox.ini ├── MANIFEST.in ├── examples ├── plot_auto_ensemble.py ├── plot_gridsearch_pipeline.py └── plot_optuna_integration.py ├── pyproject.toml ├── Makefile ├── README.md ├── .gitignore └── LICENSE /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst -------------------------------------------------------------------------------- /tests/test_ensemble/ia_sample_compile_true_t.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/casact/tryangle/HEAD/tests/test_ensemble/ia_sample_compile_true_t.npy -------------------------------------------------------------------------------- /tests/test_ensemble/ia_sample_compile_true_actual.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/casact/tryangle/HEAD/tests/test_ensemble/ia_sample_compile_true_actual.npy -------------------------------------------------------------------------------- /tests/test_ensemble/ia_sample_compile_true_expected.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/casact/tryangle/HEAD/tests/test_ensemble/ia_sample_compile_true_expected.npy -------------------------------------------------------------------------------- /src/tryangle/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | """ 6 | Utilities for Tryangle. Currently only houses sample datasets. 7 | """ 8 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | Modules 5 | ------- 6 | 7 | .. autosummary:: 8 | :toctree: _autosummary 9 | :template: custom-module-template.rst 10 | :recursive: 11 | 12 | tryangle.core 13 | tryangle.ensemble 14 | tryangle.metrics 15 | tryangle.model_selection 16 | tryangle.utils -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = {py3.9.17, py3.10.12, py3.11.4}-chainladder{0.8.14} 3 | 4 | [testenv] 5 | # install pytest in the virtualenv where commands will be executed 6 | deps = 7 | pytest 8 | chainladder0.8.14: chainladder==0.8.14 9 | commands = 10 | # NOTE: you can run any command line tool here - not just tests 11 | pytest -------------------------------------------------------------------------------- /src/tryangle/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | from tryangle.core import * # noqa (API import) 6 | from tryangle.metrics import * # noqa (API import) 7 | 8 | __version__ = "0.2.2" 9 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include requirements.txt 3 | include README.md 4 | 5 | include src/tryangle/utils/data/cas_test.csv 6 | include src/tryangle/utils/data/cas_train.csv 7 | include src/tryangle/utils/data/sme_test.csv 8 | include src/tryangle/utils/data/sme_train.csv 9 | include src/tryangle/utils/data/swiss_test.csv 10 | include src/tryangle/utils/data/swiss_train.csv -------------------------------------------------------------------------------- /src/tryangle/model_selection/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | """ 6 | The :mod:`tryangle.model_selection` module includes the TriangleSplit 7 | cross-validation splitting class. 8 | """ 9 | from tryangle.model_selection.split import TriangleSplit # noqa (API Import) 10 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. tryangle documentation master file, created by 2 | sphinx-quickstart on Tue May 18 09:01:26 2021. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to tryangle's documentation! 7 | ==================================== 8 | 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | :caption: Contents: 13 | 14 | readme 15 | modules 16 | 17 | 18 | 19 | .. Indices and tables 20 | .. ================== 21 | 22 | .. * :ref:`genindex` 23 | .. * :ref:`modindex` 24 | .. * :ref:`search` 25 | -------------------------------------------------------------------------------- /src/tryangle/metrics/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | """ 6 | The :mod:`tryangle.metrics` module includes scoring metrics used 7 | when finding the optimal reserving parameters. 8 | """ 9 | from tryangle.metrics.base import * # noqa (API Import) 10 | from tryangle.metrics.score import ( # noqa (API Import) 11 | neg_ave_scorer, 12 | neg_cdr_scorer, 13 | neg_weighted_ave_scorer, 14 | neg_weighted_cdr_scorer, 15 | ) 16 | -------------------------------------------------------------------------------- /src/tryangle/core/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | """ 6 | The :mod:`tryangle.core` module includes the TryangleData data structure 7 | and core chainladder methods. 8 | """ 9 | from tryangle.core.base import TryangleData # noqa (API Import) 10 | from tryangle.core.methods import ( # noqa (API Import) 11 | Chainladder, 12 | BornhuetterFerguson, 13 | CapeCod, 14 | VotingChainladder, 15 | ) 16 | from tryangle.core.methods import Development # noqa (API Import) 17 | -------------------------------------------------------------------------------- /src/tryangle/ensemble/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | """ 6 | The :mod:`tryangle.ensemble` module includes ensemble-based methods for 7 | VotingChainladder 8 | """ 9 | from tryangle.ensemble.base import AutoEnsemble # noqa (API Import) 10 | from tryangle.ensemble.optimizers import ( 11 | SGD, 12 | AdaGrad, 13 | RMSProp, 14 | Adam, 15 | ) # noqa (API Import) 16 | from tryangle.ensemble.losses import ( 17 | MeanSquaredError, 18 | MeanAbsolutePercentageError, 19 | ) # noqa (API Import) 20 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_templates/custom-class-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: 7 | :show-inheritance: 8 | :inherited-members: 9 | 10 | {% block methods %} 11 | .. automethod:: __init__ 12 | 13 | {% if methods %} 14 | .. rubric:: {{ _('Methods') }} 15 | 16 | .. autosummary:: 17 | {% for item in methods %} 18 | ~{{ name }}.{{ item }} 19 | {%- endfor %} 20 | {% endif %} 21 | {% endblock %} 22 | 23 | {% block attributes %} 24 | {% if attributes %} 25 | .. rubric:: {{ _('Attributes') }} 26 | 27 | .. autosummary:: 28 | {% for item in attributes %} 29 | ~{{ name }}.{{ item }} 30 | {%- endfor %} 31 | {% endif %} 32 | {% endblock %} -------------------------------------------------------------------------------- /examples/plot_auto_ensemble.py: -------------------------------------------------------------------------------- 1 | """ 2 | ====================== 3 | AutoEnsemble CL and BF 4 | ====================== 5 | 6 | Finds optimal weights to combine chainladder and bornhuetter 7 | ferguson methods to reduce prediction error. 8 | """ 9 | from tryangle.model_selection import TriangleSplit 10 | from tryangle.utils.datasets import load_sample 11 | from tryangle.ensemble import AutoEnsemble, Adam 12 | from tryangle import Chainladder, BornhuetterFerguson 13 | 14 | X = load_sample("swiss") 15 | 16 | cl = Chainladder() 17 | bf = BornhuetterFerguson(apriori=0.6) 18 | estimators = [("cl", cl), ("bf", bf)] 19 | 20 | tscv = TriangleSplit(n_splits=10) 21 | 22 | model = AutoEnsemble( 23 | estimators=estimators, 24 | cv=tscv, 25 | optimizer=Adam(learning_rate=0.01), 26 | dropout=0.1, 27 | broad_dropout=0.1, 28 | ) 29 | 30 | model.fit(X) 31 | 32 | print(model.weights_) 33 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /src/tryangle/ensemble/losses.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class MeanSquaredError: 5 | def _loss(self, y_pred, y_true): 6 | print(((y_pred - y_true))) 7 | return ((y_pred - y_true) ** 2).mean() 8 | 9 | def _loss_gradient(self, y_pred, y_true): 10 | return 2 * (y_pred - y_true) 11 | 12 | 13 | class MeanAbsolutePercentageError: 14 | def _loss(self, y_pred, y_true): 15 | _y_true = y_true + 1e-7 16 | return np.abs((y_pred - _y_true) / _y_true).mean() 17 | 18 | def _loss_gradient(self, y_pred, y_true): 19 | _y_true = y_true + 1e-7 20 | less_than_mask = y_pred < _y_true 21 | greater_than_mask = y_pred > _y_true 22 | return (1 / (_y_true.size * _y_true)) * greater_than_mask - ( 23 | 1 / (_y_true.size * _y_true) 24 | ) * less_than_mask 25 | 26 | 27 | LOSS_FUNCTIONS = { 28 | "mse": MeanSquaredError, 29 | "mape": MeanAbsolutePercentageError, 30 | } 31 | -------------------------------------------------------------------------------- /tests/test_score.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import pytest 6 | import chainladder as cl 7 | from tryangle.metrics.score import ( 8 | neg_ave_scorer, 9 | neg_weighted_ave_scorer, 10 | neg_cdr_scorer, 11 | neg_weighted_cdr_scorer, 12 | ) 13 | from tryangle.core.base import TryangleData 14 | from tryangle.core.methods import Chainladder 15 | 16 | 17 | @pytest.mark.parametrize( 18 | "scorer, true_score", 19 | [ 20 | (neg_ave_scorer, -2222.357324), 21 | (neg_weighted_ave_scorer, -2372.370821), 22 | (neg_cdr_scorer, -5064.408237), 23 | (neg_weighted_cdr_scorer, -5891.385703), 24 | ], 25 | ) 26 | def test_scorers(scorer, true_score): 27 | X = TryangleData(cl.load_sample("raa")) 28 | score = scorer(Chainladder(), X, X) 29 | assert (score - true_score) < 0.001 30 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=67.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tryangle" 7 | version = "0.2.2" 8 | description = "Tryangle Package - Scientific P&C Loss Reserving" 9 | readme = "README.md" 10 | maintainers = [{ name = "Caesar Balona", email = "caesar.balona@gmail.com" }] 11 | classifiers = [ 12 | "Intended Audience :: Financial and Insurance Industry", 13 | "Intended Audience :: Science/Research", 14 | "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", 15 | "Operating System :: OS Independent", 16 | "Programming Language :: Python :: 3", 17 | "Topic :: Office/Business :: Financial", 18 | "Topic :: Scientific/Engineering :: Artificial Intelligence", 19 | ] 20 | dependencies = ["chainladder<=0.8.14", "pandas<2.0", "scikit-learn>=1.2"] 21 | license = { text = "MPL-2.0" } 22 | requires-python = ">=3.11" 23 | 24 | [project.urls] 25 | Homepage = "https://github.com/casact/tryangle" 26 | 27 | [project.optional-dependencies] 28 | dev = ["ruff", "black", "mypy", "pytest", "tox", "twine"] 29 | 30 | -------------------------------------------------------------------------------- /examples/plot_gridsearch_pipeline.py: -------------------------------------------------------------------------------- 1 | """ 2 | ============================= 3 | GridSearchCV using a pipeline 4 | ============================= 5 | 6 | Finds the optimal development and CapeCod parameters 7 | using the unweighted CDR score. 8 | 9 | Since selecting development factors is a transformation, 10 | it can be pipelined with an estimator 11 | """ 12 | from sklearn.model_selection import GridSearchCV 13 | from sklearn.pipeline import Pipeline 14 | from tryangle import Development, CapeCod 15 | from tryangle.metrics import neg_cdr_scorer 16 | from tryangle.model_selection import TriangleSplit 17 | from tryangle.utils.datasets import load_sample 18 | 19 | X = load_sample("swiss") 20 | tscv = TriangleSplit(n_splits=5) 21 | 22 | param_grid = { 23 | "dev__n_periods": range(15, 20), 24 | "dev__drop_high": [True, False], 25 | "dev__drop_low": [True, False], 26 | "cc__decay": [0.25, 0.5, 0.75, 0.95], 27 | } 28 | 29 | pipe = Pipeline([("dev", Development()), ("cc", CapeCod())]) 30 | 31 | model = GridSearchCV( 32 | pipe, param_grid=param_grid, scoring=neg_cdr_scorer, cv=tscv, verbose=1, n_jobs=-1 33 | ) 34 | model.fit(X, X) 35 | print(model.best_params_) 36 | 37 | # TODO add plotting 38 | -------------------------------------------------------------------------------- /docs/_templates/custom-module-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | 5 | {% block attributes %} 6 | {% if attributes %} 7 | .. rubric:: Module Attributes 8 | 9 | .. autosummary:: 10 | :toctree: 11 | {% for item in attributes %} 12 | {{ item }} 13 | {%- endfor %} 14 | {% endif %} 15 | {% endblock %} 16 | 17 | {% block functions %} 18 | {% if functions %} 19 | .. rubric:: {{ _('Functions') }} 20 | 21 | .. autosummary:: 22 | :toctree: 23 | {% for item in functions %} 24 | {{ item }} 25 | {%- endfor %} 26 | {% endif %} 27 | {% endblock %} 28 | 29 | {% block classes %} 30 | {% if classes %} 31 | .. rubric:: {{ _('Classes') }} 32 | 33 | .. autosummary:: 34 | :toctree: 35 | :template: custom-class-template.rst 36 | {% for item in classes %} 37 | {{ item }} 38 | {%- endfor %} 39 | {% endif %} 40 | {% endblock %} 41 | 42 | {% block exceptions %} 43 | {% if exceptions %} 44 | .. rubric:: {{ _('Exceptions') }} 45 | 46 | .. autosummary:: 47 | :toctree: 48 | {% for item in exceptions %} 49 | {{ item }} 50 | {%- endfor %} 51 | {% endif %} 52 | {% endblock %} 53 | 54 | {% block modules %} 55 | {% if modules %} 56 | .. rubric:: Modules 57 | 58 | .. autosummary:: 59 | :toctree: 60 | :template: custom-module-template.rst 61 | :recursive: 62 | {% for item in modules %} 63 | {{ item }} 64 | {%- endfor %} 65 | {% endif %} 66 | {% endblock %} -------------------------------------------------------------------------------- /src/tryangle/metrics/base.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | 6 | def get_expected(estimator, X): 7 | """Get the expected incremental claims for the next diagonal 8 | given an estimator. 9 | 10 | Args: 11 | estimator : tryangle implementation of chainladder method 12 | X : TryangleData 13 | 14 | Returns: 15 | ndarray : Array of expected incremental claims 16 | """ 17 | valuation_date = X.latest_diagonal.valuation[0] 18 | X_test = X[X.triangle.valuation < valuation_date] 19 | 20 | expected = estimator.fit_predict(X_test) 21 | 22 | expected = expected.full_triangle_.cum_to_incr() 23 | expected = expected[expected.valuation == valuation_date].latest_diagonal 24 | 25 | return expected.to_frame().fillna(0).to_numpy() 26 | 27 | 28 | def get_actual_expected(estimator, X): 29 | """Get actual and expected given an estimator 30 | 31 | Args: 32 | estimator : tryangle implementation of chainladder method 33 | X : TryangleData 34 | 35 | Returns: 36 | (ndarray, ndarray) : Tuple of actual, expected incremental claims 37 | """ 38 | # ! TODO: Rewrite a better method that avoids fillna(0) as this could mask some error 39 | 40 | actual = X.latest_diagonal.to_frame().fillna(0).to_numpy()[:-1] 41 | expected = get_expected(estimator, X) 42 | 43 | return actual, expected 44 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: venv setup ruff format test check clean build test-publish 2 | 3 | SHELL := /bin/bash 4 | 5 | PYTHON_INTERPRETER := python 6 | VENV := source .venv/bin/activate 7 | PROJECT_CONFIG := pyproject.toml 8 | 9 | venv: .venv/touchfile 10 | 11 | .venv/touchfile: requirements.txt requirements-dev.txt 12 | $(VENV); pip-sync requirements.txt requirements-dev.txt 13 | $(VENV); pip install -e . 14 | touch .venv/touchfile 15 | 16 | requirements.txt: $(PROJECT_CONFIG) 17 | $(VENV); pip-compile --output-file=requirements.txt --resolver=backtracking $(PROJECT_CONFIG) 18 | 19 | requirements-dev.txt: $(PROJECT_CONFIG) 20 | $(VENV); pip-compile --extra=dev --output-file=requirements-dev.txt --resolver=backtracking $(PROJECT_CONFIG) 21 | 22 | test: venv 23 | $(VENV); tox 24 | 25 | build: 26 | rm -rf build dist 27 | $(VENV); python -m build 28 | 29 | test-publish: 30 | $(VENV); python -m twine upload --repository testpypi dist/* --verbose 31 | 32 | publish: 33 | $(VENV); python -m twine upload --repository tryangle dist/* --verbose 34 | 35 | setup: 36 | virtualenv .venv 37 | $(VENV); pip install --upgrade pip setuptools wheel build 38 | $(VENV); pip install pip-tools 39 | 40 | ruff: 41 | $(VENV); ruff . 42 | 43 | format: 44 | $(VENV); ruff . 45 | $(VENV); black . 46 | 47 | check: 48 | $(VENV); ruff check . 49 | $(VENV); black --check . 50 | 51 | clean: 52 | find . -type d -name ".ipynb_checkpoints" -exec rm -r {} + 53 | find . -type d -name ".pytest_cache" -exec rm -rf {} + 54 | find . -type d -name "__pycache__" -exec rm -rf {} + 55 | rm -rf build dist -------------------------------------------------------------------------------- /tests/test_split.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import pytest 6 | from sklearn.model_selection import GridSearchCV, RandomizedSearchCV 7 | from sklearn.utils.validation import check_is_fitted 8 | from tryangle.model_selection.split import TriangleSplit 9 | from tryangle.core.methods import CapeCod 10 | from tryangle.metrics.score import neg_ave_scorer 11 | from tryangle.utils.datasets import load_sample 12 | 13 | 14 | def test_split(): 15 | X = load_sample("swiss") 16 | triangle = X.triangle.copy() 17 | sample_weight = X.sample_weight.copy() 18 | tscv = TriangleSplit(n_splits=10) 19 | val_years = list(range(1988, 1998)) 20 | 21 | for i, (train_idx, _) in enumerate(tscv.split(X)): 22 | assert ( 23 | X[train_idx].triangle == triangle[triangle.valuation.year <= val_years[i]] 24 | ) 25 | assert ( 26 | X[train_idx].sample_weight 27 | == sample_weight[sample_weight.origin.year <= val_years[i]] 28 | ) 29 | 30 | 31 | @pytest.mark.parametrize("SearchClass", [(GridSearchCV), (RandomizedSearchCV)]) 32 | def test_search_methods(SearchClass): 33 | X = load_sample("swiss") 34 | tscv = TriangleSplit(n_splits=5) 35 | 36 | model = GridSearchCV( 37 | CapeCod(), 38 | param_grid={"decay": [0.2, 0.8]}, 39 | scoring=neg_ave_scorer, 40 | cv=tscv, 41 | n_jobs=1, 42 | ).fit(X, X) 43 | assert check_is_fitted(model) is None 44 | -------------------------------------------------------------------------------- /src/tryangle/model_selection/split.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import numpy as np 6 | from sklearn.model_selection._split import TimeSeriesSplit 7 | 8 | 9 | class TriangleSplit(TimeSeriesSplit): 10 | """Triangle cross-validation across calendar periods 11 | 12 | Splits a ``TryangleData`` instance into k sub-triangles or folds 13 | over the latest k calendar periods or diagonals. Thus, successive 14 | folds are supersets of previous folds. 15 | 16 | Parameters 17 | ---------- 18 | n_splits : int, default=5 19 | Number of splits, must be at least 2. 20 | """ 21 | 22 | def __init__(self, n_splits=5, *, max_train_size=None, test_size=None, gap=0): 23 | super().__init__(n_splits=n_splits, max_train_size=None, test_size=1, gap=0) 24 | 25 | def split(self, X, y=None, groups=None): 26 | valuation_date = X.triangle.latest_diagonal.valuation[0] 27 | valuation_dates = np.array( 28 | [ 29 | date 30 | for date in X.triangle.valuation.drop_duplicates().sort_values() 31 | if date.date() <= valuation_date.date() 32 | ] 33 | ) 34 | for train, test in super().split(valuation_dates): 35 | indices = np.arange(X.triangle.shape[2] * X.triangle.shape[3]) 36 | test_start = test[0] 37 | yield ( 38 | indices[X.triangle.valuation <= valuation_dates[test_start]], 39 | indices[X.triangle.valuation <= valuation_dates[test_start]], 40 | ) 41 | -------------------------------------------------------------------------------- /tests/test_datasets.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import os 6 | import pandas as pd 7 | import pytest 8 | 9 | from chainladder import Triangle 10 | from tryangle.core import TryangleData 11 | from tryangle.utils import datasets 12 | 13 | 14 | @pytest.mark.parametrize( 15 | "key", 16 | [ 17 | ("swiss"), 18 | ("cas"), 19 | ("sme"), 20 | ], 21 | ) 22 | def test_load_dataset(key): 23 | # Load TryangleData 24 | train, test = datasets.load_sample(key), datasets.load_test_sample(key) 25 | 26 | # Load raw data 27 | train_raw = pd.read_csv( 28 | os.path.join(os.path.dirname(datasets.__file__), "data", f"{key}_train.csv") 29 | ) 30 | test_raw = pd.read_csv( 31 | os.path.join(os.path.dirname(datasets.__file__), "data", f"{key}_test.csv") 32 | ) 33 | 34 | max_train_lag = train_raw.lag.max() 35 | 36 | for X, raw in zip([train, test], [train_raw, test_raw]): 37 | assert isinstance(X, TryangleData) 38 | 39 | assert isinstance(X.triangle, Triangle) 40 | if X.sample_weight: 41 | assert isinstance(X.sample_weight, Triangle) 42 | 43 | assert X.triangle.shape == (1, 1, max_train_lag + 1, max_train_lag + 1) 44 | assert X.shape == (X.triangle.shape[2] * X.triangle.shape[3], 1) 45 | 46 | if X.sample_weight: 47 | assert (X.triangle.origin == X.sample_weight.origin).all() 48 | 49 | assert (X.triangle.sum().sum() - raw.claim.sum()) < 0.01 50 | if X.sample_weight: 51 | assert (X.sample_weight.sum() - raw.claim.sum()) < 0.01 52 | 53 | assert (train.triangle.origin == test.triangle.origin).all() 54 | -------------------------------------------------------------------------------- /tests/test_methods.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import pytest 6 | import numpy as np 7 | from sklearn.pipeline import Pipeline 8 | from tryangle.core.methods import ( 9 | Benktander, 10 | BornhuetterFerguson, 11 | CapeCod, 12 | Chainladder, 13 | ClarkLDF, 14 | MackChainladder, 15 | Development, 16 | DevelopmentConstant, 17 | IncrementalAdditive, 18 | VotingChainladder, 19 | ) 20 | from tryangle.utils.datasets import load_sample 21 | 22 | base_estimators = [ 23 | Chainladder, 24 | MackChainladder, 25 | BornhuetterFerguson, 26 | CapeCod, 27 | Benktander, 28 | ] 29 | 30 | base_transformers = [ 31 | Development, 32 | DevelopmentConstant, 33 | IncrementalAdditive, 34 | ClarkLDF, 35 | ] 36 | 37 | 38 | @pytest.fixture 39 | def sample_data(): 40 | yield load_sample("swiss") 41 | 42 | 43 | @pytest.mark.parametrize("estimator", base_estimators) 44 | def test_estimators(estimator, sample_data): 45 | X = sample_data 46 | 47 | estimator().fit_predict(X) 48 | 49 | 50 | @pytest.mark.parametrize("transformer", base_transformers) 51 | def test_transformers(transformer, sample_data): 52 | X = sample_data 53 | kwargs = {} 54 | 55 | if isinstance(transformer(), DevelopmentConstant): 56 | n = len(sample_data.triangle.development) 57 | x = np.linspace(1, n, n) 58 | ldf = 1 - np.exp(-x) 59 | print(x) 60 | kwargs.update({"patterns": {(i + 1) * 12: l for i, l in enumerate(ldf)}}) 61 | 62 | transformer(**kwargs).fit_transform(X) 63 | 64 | 65 | def test_voting_estimator(sample_data): 66 | X = sample_data 67 | estimators = [ 68 | ("cl", Chainladder()), 69 | ("bf", BornhuetterFerguson()), 70 | ("cc", CapeCod()), 71 | ] 72 | VotingChainladder(estimators=estimators).fit_predict(X) 73 | 74 | 75 | def test_pipeline(sample_data): 76 | X = sample_data 77 | pipe = Pipeline([("development", Development()), ("cl", Chainladder())]) 78 | pipe.fit_predict(X) 79 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../src')) 16 | print(sys.path[0]) 17 | sys.setrecursionlimit(1500) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'tryangle' 23 | copyright = '2021, Caesar Balona & Ronald Richman' 24 | author = 'Caesar Balona & Ronald Richman' 25 | 26 | 27 | # -- General configuration --------------------------------------------------- 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.autodoc', 34 | 'sphinx.ext.napoleon', 35 | 'sphinx.ext.autosummary', 36 | ] 37 | autosummary_generate = True 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # List of patterns, relative to source directory, that match files and 43 | # directories to ignore when looking for source files. 44 | # This pattern also affects html_static_path and html_extra_path. 45 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 46 | 47 | 48 | # -- Options for HTML output ------------------------------------------------- 49 | 50 | # The theme to use for HTML and HTML Help pages. See the documentation for 51 | # a list of builtin themes. 52 | # 53 | html_theme = 'alabaster' 54 | 55 | # Add any paths that contain custom static files (such as style sheets) here, 56 | # relative to this directory. They are copied after the builtin static files, 57 | # so a file named "default.css" will overwrite the builtin "default.css". 58 | html_static_path = ['_static'] 59 | -------------------------------------------------------------------------------- /examples/plot_optuna_integration.py: -------------------------------------------------------------------------------- 1 | import optuna 2 | from optuna.visualization import ( 3 | plot_optimization_history, 4 | plot_contour, 5 | plot_param_importances, 6 | ) 7 | from joblib import Parallel, delayed 8 | from sklearn.model_selection import cross_val_score 9 | from sklearn.pipeline import Pipeline 10 | 11 | from tryangle import Development, CapeCod 12 | from tryangle.model_selection import TriangleSplit 13 | from tryangle.utils.datasets import load_sample 14 | from tryangle.metrics import neg_weighted_cdr_scorer 15 | 16 | X = load_sample("swiss") 17 | tscv = TriangleSplit(n_splits=13) 18 | 19 | 20 | def objective(trial): 21 | 22 | dev_params = { 23 | "n_periods": trial.suggest_int("dev__n_periods", 5, 19), 24 | "drop_low": trial.suggest_categorical("dev__drop_low", [True, False]), 25 | "drop_high": trial.suggest_categorical("dev__drop_high", [True, False]), 26 | } 27 | cc_params = { 28 | "decay": trial.suggest_float("cc_decay", 0.0, 1.0), 29 | "trend": trial.suggest_float("cc_trend", -1.0, 1.0), 30 | } 31 | 32 | pipe = Pipeline( 33 | [ 34 | ("dev", Development(**dev_params)), 35 | ("cc", CapeCod(**cc_params)), 36 | ] 37 | ) 38 | 39 | score = cross_val_score( 40 | pipe, X=X, y=X, scoring=neg_weighted_cdr_scorer, cv=tscv, n_jobs=1 41 | ).mean() 42 | 43 | return score 44 | 45 | 46 | def optimize(n_trials): 47 | study = optuna.load_study( 48 | study_name="opt_ibnr", storage="sqlite:///opt_ibnr.sqlite3" 49 | ) 50 | study.optimize(objective, n_trials=n_trials) 51 | 52 | 53 | study = optuna.create_study( 54 | study_name="opt_ibnr", storage="sqlite:///opt_ibnr.sqlite3", direction="maximize" 55 | ) 56 | r = Parallel(n_jobs=-1)([delayed(optimize)(1) for _ in range(100)]) 57 | 58 | print("Number of finished trials: ", len(study.trials)) 59 | print("Best trial:") 60 | trial = study.best_trial 61 | print(" Value: ", trial.value) 62 | print(" Params: ") 63 | for key, value in trial.params.items(): 64 | print(" {}: {}".format(key, value)) 65 | 66 | 67 | study = optuna.load_study(study_name="opt_ibnr", storage="sqlite:///opt_ibnr.sqlite3") 68 | 69 | plot_optimization_history(study) 70 | 71 | plot_contour(study) 72 | 73 | plot_param_importances(study) 74 | -------------------------------------------------------------------------------- /src/tryangle/core/base.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import numpy as np 6 | 7 | 8 | class TryangleData: 9 | """ 10 | TryangleData is an internal data structure used by Tryangle which is built 11 | to work with optimization libraries to allow hyperparameter optimization 12 | and parallel processing. 13 | 14 | TryangleData can only hold chainladder ``Triangle``'s that are singular in 15 | the first and second axis. That is, the shape of the ``Triangle`` must be 16 | (1, 1, n_origin, n_development). The sample_weight must also be singular 17 | in its development axis, i.e. a shape of (1, 1, n_origin, 1). 18 | 19 | Parameters 20 | ---------- 21 | triangle : chainladder ``Triangle`` object of shape (1, 1, n_origin, n_development) 22 | The loss triangle to be reserved. 23 | 24 | sample_weight : chainladder ``Triangle`` object of shape (1, 1, n_origin, 1), default=None 25 | The exposure data for exposure based methods. 26 | """ 27 | 28 | def __init__(self, triangle, sample_weight=None): 29 | self.triangle = triangle 30 | self.sample_weight = sample_weight 31 | self.shape = self.triangle.shape[2] * self.triangle.shape[3], 1 32 | self.latest_diagonal = triangle.cum_to_incr().latest_diagonal 33 | if self.latest_diagonal.shape != (): 34 | self.actual = self.latest_diagonal[ 35 | self.latest_diagonal.origin < self.latest_diagonal.origin[-1] 36 | ] 37 | 38 | def __getitem__(self, x): 39 | indices = np.full((self.shape[0],), False) 40 | indices[x] = True 41 | spliced_triangle = self.triangle[indices] 42 | if self.sample_weight is not None: 43 | sample_weight_indices = np.array( 44 | [ 45 | origin in spliced_triangle.origin 46 | for origin in self.sample_weight.origin 47 | ] 48 | ) 49 | return TryangleData( 50 | self.triangle[indices], 51 | self.sample_weight[sample_weight_indices], 52 | ) 53 | else: 54 | return TryangleData(self.triangle[indices], None) 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tryangle: Machine Learning Techniques for Chainladder Methods 2 | 3 | *Tryangle* is an automatic chainladder reserving framework. It provides 4 | scoring and optimisation methods based on machine learning techniques to 5 | automatically select optimal parameters to minimise reserve prediction 6 | error. Tryangle is built on top of the 7 | [chainladder](https://chainladder-python.readthedocs.io/en/latest/index.html) 8 | reserving package. 9 | 10 | ## Key Features 11 | 12 | Tryangle is flexible and modular in how it can be applied: 13 | 14 | - Optimising loss development factors 15 | - Use [sklearn's](https://scikit-learn.org/) GridSearchCV or RandomizedSearchCV to find the optimal 18 | method to calculate loss development factors 19 | - Choosing between multiple reserving methods 20 | - Not sure if you should go with a basic chainladder, 21 | Bornhuetter-Ferguson, or Cape-Cod method? Let Tryangle decide. 22 | - Finding the optimal blend of reserving methods 23 | - Or why not combine all three, and let Tryangle find the optimal 24 | blend. 25 | - Using advanced optimisation methods 26 | - Not satisfied with an exhaustive grid search? Tryangle can be 27 | used with any optimisation framework, but we recommend 28 | [Optuna](https://optuna.org/) 29 | 30 | ## Basic Example 31 | 32 | ``` python 33 | from sklearn.model_selection import GridSearchCV 34 | from sklearn.pipeline import Pipeline 35 | from tryangle import Development, CapeCod 36 | from tryangle.metrics import neg_cdr_scorer 37 | from tryangle.model_selection import TriangleSplit 38 | from tryangle.utils.datasets import load_sample 39 | 40 | X = load_sample("swiss") 41 | tscv = TriangleSplit(n_splits=5) 42 | 43 | param_grid = { 44 | "dev__n_periods": range(15, 20), 45 | "dev__drop_high": [True, False], 46 | "dev__drop_low": [True, False], 47 | "cc__decay": [0.25, 0.5, 0.75, 0.95], 48 | } 49 | 50 | pipe = Pipeline([("dev", Development()), ("cc", CapeCod())]) 51 | 52 | model = GridSearchCV( 53 | pipe, param_grid=param_grid, scoring=neg_cdr_scorer, cv=tscv, verbose=1, n_jobs=-1 54 | ) 55 | model.fit(X, X) 56 | ``` 57 | 58 | ## Installation 59 | 60 | Tryangle is available at [the Python Package 61 | Index](https://pypi.org/project/tryangle/). 62 | 63 | ``` console 64 | pip install tryangle 65 | ``` 66 | 67 | Tryangle supports Python 3.9. 68 | 69 | ## Reference 70 | 71 | Caesar Balona, Ronald Richman. 2021. The Actuary and IBNR Techniques: A 72 | Machine Learning Approach 73 | ([SSRN](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3697256)). 74 | -------------------------------------------------------------------------------- /src/tryangle/utils/datasets.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import os 6 | import pandas as pd 7 | from chainladder.core.triangle import Triangle 8 | from tryangle.core import TryangleData 9 | 10 | 11 | def load_sample(key, *args, **kwargs): 12 | """Function to load training datasets included in the tryangle package. 13 | 14 | Args: 15 | key (str): Key to identify dataset 16 | 17 | Returns: 18 | [TryangleData]: TryangleData object of the loaded dataset. 19 | """ 20 | path = os.path.dirname(os.path.abspath(__file__)) 21 | 22 | if key in ["swiss", "cas", "sme"]: 23 | df = pd.read_csv(os.path.join(path, "data", key.lower() + "_train.csv")) 24 | sample_weight = df[["origin", "premium", "development"]].drop_duplicates() 25 | columns = ["claim"] 26 | else: 27 | raise KeyError( 28 | "No such dataset exists. Available datasets are 'swiss', 'cas' and 'sme'." 29 | ) 30 | 31 | claim = Triangle( 32 | df, 33 | origin="origin", 34 | development="development", 35 | index=None, 36 | columns=columns, 37 | cumulative=True, 38 | *args, 39 | **kwargs 40 | ) 41 | sample_weight = Triangle( 42 | sample_weight, 43 | origin="origin", 44 | index=None, 45 | development="development", 46 | columns=["premium"], 47 | cumulative=True, 48 | *args, 49 | **kwargs 50 | ).latest_diagonal 51 | 52 | return TryangleData(claim, sample_weight) 53 | 54 | 55 | def load_test_sample(key, *args, **kwargs): 56 | """Function to load test datasets included in the tryangle package. 57 | 58 | Args: 59 | key (str): Key to identify dataset 60 | 61 | Returns: 62 | [TryangleData]: TryangleData object of the loaded dataset. 63 | """ 64 | path = os.path.dirname(os.path.abspath(__file__)) 65 | 66 | df = pd.read_csv(os.path.join(path, "data", key.lower() + "_test.csv")) 67 | 68 | claim = Triangle( 69 | df, 70 | origin="origin", 71 | development="development", 72 | index=None, 73 | columns=["claim"], 74 | cumulative=True, 75 | *args, 76 | **kwargs 77 | ) 78 | 79 | if key.lower() in ["swiss"]: 80 | claim = claim[claim.development <= 240] 81 | claim = claim[claim.origin.year <= 1997] 82 | claim = claim[claim.valuation.year > 1997] 83 | elif key.lower() in ["cas", "sme"]: 84 | claim = claim[claim.development <= 63] 85 | claim = claim[claim.origin.year <= 2014] 86 | claim = claim[claim.valuation.year > 2014] 87 | 88 | return TryangleData(claim) 89 | 90 | 91 | if __name__ == "__main__": 92 | pass 93 | -------------------------------------------------------------------------------- /tests/test_ensemble.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import os 6 | from distutils import dir_util 7 | 8 | import numpy as np 9 | import pytest 10 | from chainladder.utils import load_sample 11 | from tryangle.core.base import TryangleData 12 | from tryangle.core.methods import BornhuetterFerguson, CapeCod, Chainladder 13 | from tryangle.ensemble.base import AutoEnsemble 14 | from tryangle.model_selection.split import TriangleSplit 15 | 16 | 17 | @pytest.fixture 18 | def auto_ensemble(): 19 | estimators = [ 20 | ("cl", Chainladder()), 21 | ("bf", BornhuetterFerguson()), 22 | ("cc", CapeCod()), 23 | ] 24 | tscv = TriangleSplit(n_splits=3) 25 | yield AutoEnsemble( 26 | estimators=estimators, 27 | cv=tscv, 28 | ) 29 | 30 | 31 | @pytest.fixture 32 | def sample_data(): 33 | ia = load_sample("ia_sample") 34 | X = TryangleData(ia["loss"], ia["exposure"].latest_diagonal) 35 | yield X 36 | 37 | 38 | @pytest.fixture # https://stackoverflow.com/a/29631801 39 | def data_dir(tmpdir, request): 40 | """ 41 | Fixture responsible for searching a folder with the same name of test 42 | module and, if available, moving all contents to a temporary directory so 43 | tests can use them freely. 44 | """ 45 | filename = request.module.__file__ 46 | test_dir, _ = os.path.splitext(filename) 47 | 48 | if os.path.isdir(test_dir): 49 | dir_util.copy_tree(test_dir, str(tmpdir)) 50 | 51 | return tmpdir 52 | 53 | 54 | def test_compile(auto_ensemble, sample_data, data_dir): 55 | ens = auto_ensemble 56 | X = sample_data 57 | ens.compile(X) 58 | 59 | with open(data_dir.join("ia_sample_compile_true_actual.npy"), "rb") as f: 60 | true_actual = np.load(f, allow_pickle=True) 61 | assert ens.actual_.shape == (3, 6, 1) 62 | assert np.allclose(ens.actual_, true_actual) 63 | 64 | with open(data_dir.join("ia_sample_compile_true_expected.npy"), "rb") as f: 65 | true_expected = np.load(f, allow_pickle=True) 66 | assert ens.expected_.shape == (3, 6, 3) 67 | assert np.allclose(ens.expected_, true_expected) 68 | 69 | with open(data_dir.join("ia_sample_compile_true_t.npy"), "rb") as f: 70 | true_t = np.load(f, allow_pickle=True) 71 | assert ens.t_.shape == (3, 6, 1) 72 | assert np.allclose(ens.t_, true_t) 73 | 74 | 75 | def test_softmax(auto_ensemble): 76 | ens = auto_ensemble 77 | assert np.allclose( 78 | ens._softmax(np.stack((-np.ones((5, 2)), np.zeros((5, 2)), np.ones((5, 2))))), 79 | 0.5 * np.ones((3, 5, 2)), 80 | ) 81 | 82 | 83 | def test_softmax_gradient(auto_ensemble): 84 | ens = auto_ensemble 85 | assert np.allclose( 86 | ens._softmax_gradient(0.5 * np.ones((3, 5, 2))), 87 | -0.25 * np.ones((3, 5, 2, 2)) + 0.5 * np.eye(2), 88 | ) 89 | 90 | 91 | # TODO: Expand tests on finalisation of autoensemble 92 | -------------------------------------------------------------------------------- /src/tryangle/metrics/score.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import numpy as np 6 | 7 | from tryangle.metrics.base import get_actual_expected 8 | 9 | from sklearn.metrics._scorer import _BaseScorer 10 | from sklearn.metrics import mean_squared_error 11 | 12 | 13 | class AVEScore(_BaseScorer): 14 | """Base AvE scoring class""" 15 | 16 | def __init__( 17 | self, 18 | score_func=mean_squared_error, 19 | sign=-1, 20 | kwargs={"squared": False}, 21 | weighted=False, 22 | ): 23 | self.weighted = weighted 24 | super().__init__(score_func, sign, kwargs) 25 | 26 | def _sample_weight(self, X, valuation_date): 27 | X_prior = X[X.triangle.valuation < valuation_date] 28 | return np.abs( 29 | X.triangle.latest_diagonal.to_frame().to_numpy()[:-1] 30 | - X_prior.triangle.latest_diagonal.to_frame().to_numpy() 31 | ) 32 | 33 | def _score(self, method_caller, estimator, X, y_true=None, sample_weight=None): 34 | """Evaluate predicted target values for X relative to y_true.""" # TODO: Update docstring 35 | 36 | valuation_date = X.triangle.cum_to_incr().latest_diagonal.valuation[0] 37 | actual, expected = get_actual_expected(estimator, X) 38 | 39 | if self.weighted: 40 | sample_weight = self._sample_weight(X, valuation_date) 41 | return self._sign * self._score_func( 42 | actual, expected, sample_weight=sample_weight, **self._kwargs 43 | ) 44 | else: 45 | return self._sign * self._score_func(actual, expected, **self._kwargs) 46 | 47 | 48 | class CDRScore(AVEScore): 49 | """Base CDR scoring class""" 50 | 51 | def _score(self, method_caller, estimator, X, y_true, sample_weight=None): 52 | """Evaluate predicted target values for X relative to y_true.""" # TODO: Update docstring 53 | 54 | valuation_date = y_true.triangle.latest_diagonal.valuation[0] 55 | X_k = X[X.triangle.valuation < valuation_date] 56 | X_k_1 = X 57 | 58 | # We only need actual as the expected will be in ibnr_k 59 | actual, _ = get_actual_expected(estimator, X) 60 | 61 | # ! TODO: Rewrite a better method that avoids fillna(0) as this could mask some error 62 | ibnr_k = estimator.fit_predict(X_k).ibnr_.to_frame().fillna(0).to_numpy() 63 | ibnr_k_1 = ( 64 | estimator.fit_predict(X_k_1).ibnr_.to_frame().fillna(0).to_numpy()[:-1] 65 | ) 66 | 67 | if self.weighted: 68 | sample_weight = super()._sample_weight(X, valuation_date) 69 | return self._sign * self._score_func( 70 | actual + ibnr_k_1, ibnr_k, sample_weight=sample_weight, **self._kwargs 71 | ) 72 | else: 73 | return self._sign * self._score_func( 74 | actual + ibnr_k_1, ibnr_k, **self._kwargs 75 | ) 76 | 77 | 78 | neg_ave_scorer = AVEScore() 79 | neg_weighted_ave_scorer = AVEScore(weighted=True) 80 | neg_cdr_scorer = CDRScore() 81 | neg_weighted_cdr_scorer = CDRScore(weighted=True) 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/python,jupyternotebooks,visualstudiocode 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=python,jupyternotebooks,visualstudiocode 3 | 4 | ### JupyterNotebooks ### 5 | # gitignore template for Jupyter Notebooks 6 | # website: http://jupyter.org/ 7 | 8 | .ipynb_checkpoints 9 | */.ipynb_checkpoints/* 10 | 11 | # IPython 12 | profile_default/ 13 | ipython_config.py 14 | 15 | # Remove previous ipynb_checkpoints 16 | # git rm -r .ipynb_checkpoints/ 17 | 18 | ### Python ### 19 | # Byte-compiled / optimized / DLL files 20 | __pycache__/ 21 | *.py[cod] 22 | *$py.class 23 | 24 | # C extensions 25 | *.so 26 | 27 | # Distribution / packaging 28 | .Python 29 | build/ 30 | develop-eggs/ 31 | dist/ 32 | downloads/ 33 | eggs/ 34 | .eggs/ 35 | parts/ 36 | sdist/ 37 | var/ 38 | wheels/ 39 | pip-wheel-metadata/ 40 | share/python-wheels/ 41 | *.egg-info/ 42 | .installed.cfg 43 | *.egg 44 | MANIFEST 45 | 46 | # PyInstaller 47 | # Usually these files are written by a python script from a template 48 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 49 | *.manifest 50 | *.spec 51 | 52 | # Installer logs 53 | pip-log.txt 54 | pip-delete-this-directory.txt 55 | 56 | # Unit test / coverage reports 57 | htmlcov/ 58 | .tox/ 59 | .nox/ 60 | .coverage 61 | .coverage.* 62 | .cache 63 | nosetests.xml 64 | coverage.xml 65 | *.cover 66 | *.py,cover 67 | .hypothesis/ 68 | .pytest_cache/ 69 | pytestdebug.log 70 | 71 | # Translations 72 | *.mo 73 | *.pot 74 | 75 | # Django stuff: 76 | *.log 77 | local_settings.py 78 | db.sqlite3 79 | db.sqlite3-journal 80 | 81 | # Flask stuff: 82 | instance/ 83 | .webassets-cache 84 | 85 | # Scrapy stuff: 86 | .scrapy 87 | 88 | # Sphinx documentation 89 | docs/_build/ 90 | doc/_build/ 91 | docs/_autosummary/ 92 | 93 | # PyBuilder 94 | target/ 95 | 96 | # Jupyter Notebook 97 | 98 | # IPython 99 | 100 | # pyenv 101 | .python-version 102 | 103 | # pipenv 104 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 105 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 106 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 107 | # install all needed dependencies. 108 | #Pipfile.lock 109 | 110 | # poetry 111 | #poetry.lock 112 | 113 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 114 | __pypackages__/ 115 | 116 | # Celery stuff 117 | celerybeat-schedule 118 | celerybeat.pid 119 | 120 | # SageMath parsed files 121 | *.sage.py 122 | 123 | # Environments 124 | # .env 125 | .env/ 126 | .venv/ 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | pythonenv* 133 | 134 | # Spyder project settings 135 | .spyderproject 136 | .spyproject 137 | 138 | # Rope project settings 139 | .ropeproject 140 | 141 | # mkdocs documentation 142 | /site 143 | 144 | # mypy 145 | .mypy_cache/ 146 | .dmypy.json 147 | dmypy.json 148 | 149 | # Pyre type checker 150 | .pyre/ 151 | 152 | # pytype static type analyzer 153 | .pytype/ 154 | 155 | # operating system-related files 156 | # file properties cache/storage on macOS 157 | *.DS_Store 158 | # thumbnail cache on Windows 159 | Thumbs.db 160 | 161 | # profiling data 162 | .prof 163 | 164 | 165 | ### VisualStudioCode ### 166 | .vscode/* 167 | *.code-workspace 168 | 169 | ### VisualStudioCode Patch ### 170 | # Ignore all local history of files 171 | .history 172 | .ionide 173 | 174 | # End of https://www.toptal.com/developers/gitignore/api/python,jupyternotebooks,visualstudiocode 175 | 176 | 177 | ### Project ### 178 | requirements.txt 179 | requirements-dev.txt -------------------------------------------------------------------------------- /src/tryangle/utils/data/swiss_train.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 1979,1979,0,3670,17684 3 | 1979,1980,1,5817,17684 4 | 1979,1981,2,6462,17684 5 | 1979,1982,3,6671,17684 6 | 1979,1983,4,6775,17684 7 | 1979,1984,5,7002,17684 8 | 1979,1985,6,7034,17684 9 | 1979,1986,7,7096,17684 10 | 1979,1987,8,7204,17684 11 | 1979,1988,9,7326,17684 12 | 1979,1989,10,7395,17684 13 | 1979,1990,11,7438,17684 14 | 1979,1991,12,7468,17684 15 | 1979,1992,13,7541,17684 16 | 1979,1993,14,7580,17684 17 | 1979,1994,15,7677,17684 18 | 1979,1995,16,7794,17684 19 | 1979,1996,17,7919,17684 20 | 1979,1997,18,8047,17684 21 | 1980,1980,0,4827,18762 22 | 1980,1981,1,7600,18762 23 | 1980,1982,2,8274,18762 24 | 1980,1983,3,8412,18762 25 | 1980,1984,4,9059,18762 26 | 1980,1985,5,9197,18762 27 | 1980,1986,6,9230,18762 28 | 1980,1987,7,9277,18762 29 | 1980,1988,8,9331,18762 30 | 1980,1989,9,9435,18762 31 | 1980,1990,10,9864,18762 32 | 1980,1991,11,9621,18762 33 | 1980,1992,12,9654,18762 34 | 1980,1993,13,9704,18762 35 | 1980,1994,14,9743,18762 36 | 1980,1995,15,9745,18762 37 | 1980,1996,16,9745,18762 38 | 1980,1997,17,9748,18762 39 | 1981,1981,0,7130,22056 40 | 1981,1982,1,10852,22056 41 | 1981,1983,2,11422,22056 42 | 1981,1984,3,12024,22056 43 | 1981,1985,4,12320,22056 44 | 1981,1986,5,12346,22056 45 | 1981,1987,6,12379,22056 46 | 1981,1988,7,12426,22056 47 | 1981,1989,8,12460,22056 48 | 1981,1990,9,12500,22056 49 | 1981,1991,10,12508,22056 50 | 1981,1992,11,12547,22056 51 | 1981,1993,12,12557,22056 52 | 1981,1994,13,12624,22056 53 | 1981,1995,14,12639,22056 54 | 1981,1996,15,12644,22056 55 | 1981,1997,16,12647,22056 56 | 1982,1982,0,9244,25489 57 | 1982,1983,1,13340,25489 58 | 1982,1984,2,13758,25489 59 | 1982,1985,3,13853,25489 60 | 1982,1986,4,13894,25489 61 | 1982,1987,5,13942,25489 62 | 1982,1988,6,13980,25489 63 | 1982,1989,7,14001,25489 64 | 1982,1990,8,14012,25489 65 | 1982,1991,9,14070,25489 66 | 1982,1992,10,14085,25489 67 | 1982,1993,11,14098,25489 68 | 1982,1994,12,14111,25489 69 | 1982,1995,13,14118,25489 70 | 1982,1996,14,14120,25489 71 | 1982,1997,15,14133,25489 72 | 1983,1983,0,10019,24819 73 | 1983,1984,1,14223,24819 74 | 1983,1985,2,15403,24819 75 | 1983,1986,3,15579,24819 76 | 1983,1987,4,15732,24819 77 | 1983,1988,5,15921,24819 78 | 1983,1989,6,16187,24819 79 | 1983,1990,7,16420,24819 80 | 1983,1991,8,16531,24819 81 | 1983,1992,9,16559,24819 82 | 1983,1993,10,16568,24819 83 | 1983,1994,11,16585,24819 84 | 1983,1995,12,16597,24819 85 | 1983,1996,13,16614,24819 86 | 1983,1997,14,16617,24819 87 | 1984,1984,0,9966,26887 88 | 1984,1985,1,14599,26887 89 | 1984,1986,2,15181,26887 90 | 1984,1987,3,15431,26887 91 | 1984,1988,4,15506,26887 92 | 1984,1989,5,15538,26887 93 | 1984,1990,6,15906,26887 94 | 1984,1991,7,16014,26887 95 | 1984,1992,8,16537,26887 96 | 1984,1993,9,16833,26887 97 | 1984,1994,10,16951,26887 98 | 1984,1995,11,17038,26887 99 | 1984,1996,12,17040,26887 100 | 1984,1997,13,17195,26887 101 | 1985,1985,0,10441,31782 102 | 1985,1986,1,15043,31782 103 | 1985,1987,2,15577,31782 104 | 1985,1988,3,15784,31782 105 | 1985,1989,4,15926,31782 106 | 1985,1990,5,16054,31782 107 | 1985,1991,6,16087,31782 108 | 1985,1992,7,16107,31782 109 | 1985,1993,8,16311,31782 110 | 1985,1994,9,16366,31782 111 | 1985,1995,10,16396,31782 112 | 1985,1996,11,16414,31782 113 | 1985,1997,12,16419,31782 114 | 1986,1986,0,10578,32585 115 | 1986,1987,1,15657,32585 116 | 1986,1988,2,16352,32585 117 | 1986,1989,3,16714,32585 118 | 1986,1990,4,17048,32585 119 | 1986,1991,5,17289,32585 120 | 1986,1992,6,17632,32585 121 | 1986,1993,7,17646,32585 122 | 1986,1994,8,17662,32585 123 | 1986,1995,9,17678,32585 124 | 1986,1996,10,17693,32585 125 | 1986,1997,11,17700,32585 126 | 1987,1987,0,11214,32726 127 | 1987,1988,1,16482,32726 128 | 1987,1989,2,17197,32726 129 | 1987,1990,3,17518,32726 130 | 1987,1991,4,18345,32726 131 | 1987,1992,5,18480,32726 132 | 1987,1993,6,18505,32726 133 | 1987,1994,7,18520,32726 134 | 1987,1995,8,18578,32726 135 | 1987,1996,9,18633,32726 136 | 1987,1997,10,18671,32726 137 | 1988,1988,0,11442,36372 138 | 1988,1989,1,17621,36372 139 | 1988,1990,2,18465,36372 140 | 1988,1991,3,18693,36372 141 | 1988,1992,4,18882,36372 142 | 1988,1993,5,18965,36372 143 | 1988,1994,6,20464,36372 144 | 1988,1995,7,20522,36372 145 | 1988,1996,8,20558,36372 146 | 1988,1997,9,20607,36372 147 | 1989,1989,0,11720,36873 148 | 1989,1990,1,17779,36873 149 | 1989,1991,2,18655,36873 150 | 1989,1992,3,18940,36873 151 | 1989,1993,4,19098,36873 152 | 1989,1994,5,19368,36873 153 | 1989,1995,6,19970,36873 154 | 1989,1996,7,20162,36873 155 | 1989,1997,8,20195,36873 156 | 1990,1990,0,13293,38938 157 | 1990,1991,1,20689,38938 158 | 1990,1992,2,21696,38938 159 | 1990,1993,3,22439,38938 160 | 1990,1994,4,22798,38938 161 | 1990,1995,5,23054,38938 162 | 1990,1996,6,23394,38938 163 | 1990,1997,7,23554,38938 164 | 1991,1991,0,15063,42109 165 | 1991,1992,1,22917,42109 166 | 1991,1993,2,23543,42109 167 | 1991,1994,3,24032,42109 168 | 1991,1995,4,24156,42109 169 | 1991,1996,5,24232,42109 170 | 1991,1997,6,24360,42109 171 | 1992,1992,0,16986,40818 172 | 1992,1993,1,23958,40818 173 | 1992,1994,2,25090,40818 174 | 1992,1995,3,25392,40818 175 | 1992,1996,4,25546,40818 176 | 1992,1997,5,26099,40818 177 | 1993,1993,0,16681,43180 178 | 1993,1994,1,24867,43180 179 | 1993,1995,2,25871,43180 180 | 1993,1996,3,26463,43180 181 | 1993,1997,4,26941,43180 182 | 1994,1994,0,17595,47061 183 | 1994,1995,1,25152,47061 184 | 1994,1996,2,26140,47061 185 | 1994,1997,3,27090,47061 186 | 1995,1995,0,16547,48428 187 | 1995,1996,1,25396,48428 188 | 1995,1997,2,26506,48428 189 | 1996,1996,0,15449,52565 190 | 1996,1997,1,22702,52565 191 | 1997,1997,0,18043,52728 192 | -------------------------------------------------------------------------------- /src/tryangle/core/methods.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | from chainladder.development.clark import ClarkLDF as _cl_ClarkLDF 6 | from chainladder.development.constant import ( 7 | DevelopmentConstant as _cl_DevelopmentConstant, 8 | ) 9 | from chainladder.development.development import Development as _cl_Development 10 | from chainladder.development.incremental import ( 11 | IncrementalAdditive as _cl_IncrementalAdditive, 12 | ) 13 | from chainladder.methods.benktander import Benktander as _cl_Benktander 14 | from chainladder.methods.bornferg import BornhuetterFerguson as _cl_BornhuetterFerguson 15 | from chainladder.methods.capecod import CapeCod as _cl_CapeCod 16 | from chainladder.methods.chainladder import Chainladder as _cl_Chainladder 17 | from chainladder.methods.mack import MackChainladder as _cl_MackChainladder 18 | from chainladder.workflow.voting import VotingChainladder as _cl_VotingChainladder 19 | from tryangle.core.base import TryangleData 20 | 21 | 22 | class EstimatorMixin: 23 | """ 24 | Fit and predict a chainladder estimator 25 | """ 26 | 27 | def fit(self, X, y=None, sample_weight=None): 28 | return super().fit(X.triangle, y=None, sample_weight=X.sample_weight) 29 | 30 | def predict(self, X, sample_weight=None): 31 | return super().predict(X.triangle, sample_weight=X.sample_weight) 32 | 33 | def fit_predict(self, X, sample_weight=None): 34 | self.fit(X) 35 | return self.predict(X) 36 | 37 | 38 | class TransformerMixin: 39 | """ 40 | Fit and transform a chainladder transfomer 41 | """ 42 | 43 | def fit(self, X, y=None, sample_weight=None): 44 | return super().fit(X.triangle, y=None, sample_weight=X.sample_weight) 45 | 46 | def transform(self, X): 47 | return TryangleData(super().transform(X.triangle), X.sample_weight) 48 | 49 | 50 | class Development(TransformerMixin, _cl_Development): 51 | __doc__ = _cl_Development.__doc__ 52 | 53 | def __init__( 54 | self, 55 | n_periods=-1, 56 | average="volume", 57 | sigma_interpolation="log-linear", 58 | drop=None, 59 | drop_high=None, 60 | drop_low=None, 61 | drop_valuation=None, 62 | fillna=None, 63 | ): 64 | super().__init__( 65 | n_periods=n_periods, 66 | average=average, 67 | sigma_interpolation=sigma_interpolation, 68 | drop=drop, 69 | drop_high=drop_high, 70 | drop_low=drop_low, 71 | drop_valuation=drop_valuation, 72 | fillna=fillna, 73 | ) 74 | 75 | 76 | class DevelopmentConstant(TransformerMixin, _cl_DevelopmentConstant): 77 | __doc__ = _cl_DevelopmentConstant.__doc__ 78 | 79 | def __init__( 80 | self, 81 | patterns=None, 82 | style="ldf", 83 | callable_axis=0, 84 | ): 85 | super().__init__( 86 | patterns=patterns, 87 | style=style, 88 | callable_axis=callable_axis, 89 | ) 90 | 91 | 92 | class IncrementalAdditive(TransformerMixin, _cl_IncrementalAdditive): 93 | __doc__ = _cl_IncrementalAdditive.__doc__ 94 | 95 | def __init__( 96 | self, 97 | trend=0.0, 98 | n_periods=-1, 99 | average="volume", 100 | future_trend=0, 101 | drop=None, 102 | drop_high=None, 103 | drop_low=None, 104 | drop_valuation=None, 105 | ): 106 | super().__init__( 107 | trend=trend, 108 | n_periods=n_periods, 109 | average=average, 110 | future_trend=future_trend, 111 | drop=drop, 112 | drop_high=drop_high, 113 | drop_low=drop_low, 114 | drop_valuation=drop_valuation, 115 | ) 116 | 117 | 118 | class ClarkLDF(TransformerMixin, _cl_ClarkLDF): 119 | __doc__ = _cl_ClarkLDF.__doc__ 120 | 121 | def __init__(self, growth="loglogistic"): 122 | super().__init__( 123 | growth=growth, 124 | ) 125 | 126 | 127 | class Chainladder(EstimatorMixin, _cl_Chainladder): 128 | __doc__ = _cl_Chainladder.__doc__ 129 | 130 | 131 | class MackChainladder(EstimatorMixin, _cl_MackChainladder): 132 | __doc__ = _cl_MackChainladder.__doc__ 133 | 134 | 135 | class BornhuetterFerguson(EstimatorMixin, _cl_BornhuetterFerguson): 136 | __doc__ = _cl_BornhuetterFerguson.__doc__ 137 | 138 | def __init__(self, apriori=1.0, apriori_sigma=0.0, random_state=None): 139 | super().__init__( 140 | apriori=apriori, apriori_sigma=apriori_sigma, random_state=random_state 141 | ) 142 | 143 | 144 | class CapeCod(EstimatorMixin, _cl_CapeCod): 145 | __doc__ = _cl_CapeCod.__doc__ 146 | 147 | def __init__(self, trend=0, decay=1): 148 | super().__init__(trend=trend, decay=decay) 149 | 150 | 151 | class Benktander(EstimatorMixin, _cl_Benktander): 152 | __doc__ = _cl_Benktander.__doc__ 153 | 154 | def __init__(self, apriori=1.0, n_iters=1, apriori_sigma=0, random_state=None): 155 | super().__init__( 156 | apriori=apriori, 157 | n_iters=n_iters, 158 | apriori_sigma=apriori_sigma, 159 | random_state=random_state, 160 | ) 161 | 162 | 163 | class VotingChainladder(EstimatorMixin, _cl_VotingChainladder): 164 | __doc__ = _cl_VotingChainladder.__doc__ 165 | 166 | def __init__( 167 | self, 168 | estimators, 169 | weights=None, 170 | default_weighting=None, 171 | n_jobs=None, 172 | verbose=False, 173 | ): 174 | # Convert tryangle estimators to chainladder estimators 175 | estimators = [ 176 | ( 177 | name, 178 | globals()["_cl_" + estimator.__class__.__name__](**estimator.__dict__), 179 | ) 180 | for name, estimator in estimators 181 | ] 182 | super().__init__( 183 | estimators=estimators, 184 | weights=weights, 185 | default_weighting=default_weighting, 186 | n_jobs=n_jobs, 187 | verbose=verbose, 188 | ) 189 | -------------------------------------------------------------------------------- /src/tryangle/utils/data/cas_test.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 2010/03/31,2015/03/31,20,9455.582936,0 3 | 2010/06/30,2015/03/31,19,5807.656259,0 4 | 2010/06/30,2015/06/30,20,5802.727068,0 5 | 2010/09/30,2015/03/31,18,7821.904961,0 6 | 2010/09/30,2015/06/30,19,7821.405067,0 7 | 2010/09/30,2015/09/30,20,8155.834385,0 8 | 2010/12/31,2015/03/31,17,5920.818388,0 9 | 2010/12/31,2015/06/30,18,6165.941,0 10 | 2010/12/31,2015/09/30,19,6196.027664,0 11 | 2010/12/31,2015/12/31,20,6026.017085,0 12 | 2011/03/31,2015/03/31,16,8708.868662,0 13 | 2011/03/31,2015/06/30,17,9367.636407,0 14 | 2011/03/31,2015/09/30,18,9670.723512,0 15 | 2011/03/31,2015/12/31,19,10318.90047,0 16 | 2011/03/31,2016/03/31,20,10078.6838,0 17 | 2011/06/30,2015/03/31,15,7050.81212,0 18 | 2011/06/30,2015/06/30,16,6987.592923,0 19 | 2011/06/30,2015/09/30,17,7024.759487,0 20 | 2011/06/30,2015/12/31,18,7182.156453,0 21 | 2011/06/30,2016/03/31,19,6672.333972,0 22 | 2011/06/30,2016/06/30,20,6675.705353,0 23 | 2011/09/30,2015/03/31,14,8560.597674,0 24 | 2011/09/30,2015/06/30,15,8368.7545,0 25 | 2011/09/30,2015/09/30,16,8322.810722,0 26 | 2011/09/30,2015/12/31,17,8495.471904,0 27 | 2011/09/30,2016/03/31,18,8286.097551,0 28 | 2011/09/30,2016/06/30,19,8254.976221,0 29 | 2011/09/30,2016/09/30,20,8536.265608,0 30 | 2011/12/31,2015/03/31,13,9206.937813,0 31 | 2011/12/31,2015/06/30,14,9792.186212,0 32 | 2011/12/31,2015/09/30,15,9953.245195,0 33 | 2011/12/31,2015/12/31,16,10001.54894,0 34 | 2011/12/31,2016/03/31,17,9407.197813,0 35 | 2011/12/31,2016/06/30,18,9451.769788,0 36 | 2011/12/31,2016/09/30,19,8273.228178,0 37 | 2011/12/31,2016/12/31,20,8370.95171,0 38 | 2012/03/31,2015/03/31,12,2504.505551,0 39 | 2012/03/31,2015/06/30,13,2677.771256,0 40 | 2012/03/31,2015/09/30,14,2594.393529,0 41 | 2012/03/31,2015/12/31,15,2648.196111,0 42 | 2012/03/31,2016/03/31,16,2660.832975,0 43 | 2012/03/31,2016/06/30,17,2521.048566,0 44 | 2012/03/31,2016/09/30,18,2529.395639,0 45 | 2012/03/31,2016/12/31,19,2370.231604,0 46 | 2012/03/31,2017/03/31,20,2370.231604,0 47 | 2012/06/30,2015/03/31,11,4719.5839,0 48 | 2012/06/30,2015/06/30,12,5136.530661,0 49 | 2012/06/30,2015/09/30,13,5207.515658,0 50 | 2012/06/30,2015/12/31,14,5588.958295,0 51 | 2012/06/30,2016/03/31,15,6253.538765,0 52 | 2012/06/30,2016/06/30,16,6507.101453,0 53 | 2012/06/30,2016/09/30,17,6507.101453,0 54 | 2012/06/30,2016/12/31,18,6593.048404,0 55 | 2012/06/30,2017/03/31,19,6603.650814,0 56 | 2012/06/30,2017/06/30,20,6659.034458,0 57 | 2012/09/30,2015/03/31,10,7024.701359,0 58 | 2012/09/30,2015/06/30,11,7046.092187,0 59 | 2012/09/30,2015/09/30,12,7394.181408,0 60 | 2012/09/30,2015/12/31,13,10204.44792,0 61 | 2012/09/30,2016/03/31,14,9914.892836,0 62 | 2012/09/30,2016/06/30,15,9643.392079,0 63 | 2012/09/30,2016/09/30,16,9928.971256,0 64 | 2012/09/30,2016/12/31,17,10268.88779,0 65 | 2012/09/30,2017/03/31,18,10221.3397,0 66 | 2012/09/30,2017/06/30,19,10808.43654,0 67 | 2012/09/30,2017/09/30,20,10913.05397,0 68 | 2012/12/31,2015/03/31,9,4983.900129,0 69 | 2012/12/31,2015/06/30,10,4971.553901,0 70 | 2012/12/31,2015/09/30,11,5328.397086,0 71 | 2012/12/31,2015/12/31,12,5752.481874,0 72 | 2012/12/31,2016/03/31,13,5802.343428,0 73 | 2012/12/31,2016/06/30,14,5553.616928,0 74 | 2012/12/31,2016/09/30,15,6082.888786,0 75 | 2012/12/31,2016/12/31,16,6529.6432,0 76 | 2012/12/31,2017/03/31,17,6522.784185,0 77 | 2012/12/31,2017/06/30,18,6564.868313,0 78 | 2012/12/31,2017/09/30,19,6569.704501,0 79 | 2012/12/31,2017/12/31,20,6519.645313,0 80 | 2013/03/31,2015/03/31,8,4766.701849,0 81 | 2013/03/31,2015/06/30,9,5146.912188,0 82 | 2013/03/31,2015/09/30,10,5977.108817,0 83 | 2013/03/31,2015/12/31,11,5955.415727,0 84 | 2013/03/31,2016/03/31,12,6004.498377,0 85 | 2013/03/31,2016/06/30,13,6077.296944,0 86 | 2013/03/31,2016/09/30,14,6227.974401,0 87 | 2013/03/31,2016/12/31,15,6501.928128,0 88 | 2013/03/31,2017/03/31,16,6590.22342,0 89 | 2013/03/31,2017/06/30,17,6602.709153,0 90 | 2013/03/31,2017/09/30,18,7606.764385,0 91 | 2013/03/31,2017/12/31,19,7754.256468,0 92 | 2013/03/31,2018/03/31,20,7754.256468,0 93 | 2013/06/30,2015/03/31,7,10614.36128,0 94 | 2013/06/30,2015/06/30,8,11270.87369,0 95 | 2013/06/30,2015/09/30,9,11901.05445,0 96 | 2013/06/30,2015/12/31,10,11493.18717,0 97 | 2013/06/30,2016/03/31,11,11492.57102,0 98 | 2013/06/30,2016/06/30,12,11778.18507,0 99 | 2013/06/30,2016/09/30,13,11795.65812,0 100 | 2013/06/30,2016/12/31,14,11238.04342,0 101 | 2013/06/30,2017/03/31,15,11358.48308,0 102 | 2013/06/30,2017/06/30,16,11098.73565,0 103 | 2013/06/30,2017/09/30,17,11107.0711,0 104 | 2013/06/30,2017/12/31,18,11450.11487,0 105 | 2013/06/30,2018/03/31,19,11413.3087,0 106 | 2013/06/30,2018/06/30,20,11607.40721,0 107 | 2013/09/30,2015/03/31,6,4882.154192,0 108 | 2013/09/30,2015/06/30,7,4970.077469,0 109 | 2013/09/30,2015/09/30,8,4877.07387,0 110 | 2013/09/30,2015/12/31,9,5969.377893,0 111 | 2013/09/30,2016/03/31,10,6023.157224,0 112 | 2013/09/30,2016/06/30,11,6167.719694,0 113 | 2013/09/30,2016/09/30,12,6383.557797,0 114 | 2013/09/30,2016/12/31,13,7814.511175,0 115 | 2013/09/30,2017/03/31,14,7804.362157,0 116 | 2013/09/30,2017/06/30,15,7262.162799,0 117 | 2013/09/30,2017/09/30,16,8047.078301,0 118 | 2013/09/30,2017/12/31,17,8041.846848,0 119 | 2013/09/30,2018/03/31,18,8288.318012,0 120 | 2013/09/30,2018/06/30,19,8340.237271,0 121 | 2013/09/30,2018/09/30,20,8329.809243,0 122 | 2013/12/31,2015/03/31,5,7356.631205,0 123 | 2013/12/31,2015/06/30,6,7117.693333,0 124 | 2013/12/31,2015/09/30,7,7671.250756,0 125 | 2013/12/31,2015/12/31,8,7983.905606,0 126 | 2013/12/31,2016/03/31,9,8775.831254,0 127 | 2013/12/31,2016/06/30,10,9575.278568,0 128 | 2013/12/31,2016/09/30,11,9614.851599,0 129 | 2013/12/31,2016/12/31,12,9884.143521,0 130 | 2013/12/31,2017/03/31,13,9907.88269,0 131 | 2013/12/31,2017/06/30,14,7871.127116,0 132 | 2013/12/31,2017/09/30,15,8005.029048,0 133 | 2013/12/31,2017/12/31,16,7982.185039,0 134 | 2013/12/31,2018/03/31,17,7897.8424,0 135 | 2013/12/31,2018/06/30,18,7899.597843,0 136 | 2013/12/31,2018/09/30,19,7894.447769,0 137 | 2013/12/31,2018/12/31,20,7732.237866,0 138 | 2014/03/31,2015/03/31,4,5070.777116,0 139 | 2014/03/31,2015/06/30,5,5653.839931,0 140 | 2014/03/31,2015/09/30,6,6389.265893,0 141 | 2014/03/31,2015/12/31,7,7468.130895,0 142 | 2014/03/31,2016/03/31,8,7458.226012,0 143 | 2014/03/31,2016/06/30,9,7303.293641,0 144 | 2014/03/31,2016/09/30,10,7229.983554,0 145 | 2014/03/31,2016/12/31,11,7365.826936,0 146 | 2014/03/31,2017/03/31,12,7498.264061,0 147 | 2014/03/31,2017/06/30,13,8081.245498,0 148 | 2014/03/31,2017/09/30,14,8312.684955,0 149 | 2014/03/31,2017/12/31,15,8778.70274,0 150 | 2014/03/31,2018/03/31,16,8854.465797,0 151 | 2014/03/31,2018/06/30,17,9395.583989,0 152 | 2014/03/31,2018/09/30,18,9567.431389,0 153 | 2014/03/31,2018/12/31,19,10067.05835,0 154 | 2014/03/31,2019/03/31,20,10907.65976,0 155 | 2014/06/30,2015/03/31,3,10026.34602,0 156 | 2014/06/30,2015/06/30,4,10224.50182,0 157 | 2014/06/30,2015/09/30,5,10712.86372,0 158 | 2014/06/30,2015/12/31,6,11673.96291,0 159 | 2014/06/30,2016/03/31,7,11833.42921,0 160 | 2014/06/30,2016/06/30,8,11639.13306,0 161 | 2014/06/30,2016/09/30,9,12485.36119,0 162 | 2014/06/30,2016/12/31,10,12278.86995,0 163 | 2014/06/30,2017/03/31,11,12327.17369,0 164 | 2014/06/30,2017/06/30,12,11754.22502,0 165 | 2014/06/30,2017/09/30,13,11808.58562,0 166 | 2014/06/30,2017/12/31,14,11776.18549,0 167 | 2014/06/30,2018/03/31,15,11853.77375,0 168 | 2014/06/30,2018/06/30,16,11686.86716,0 169 | 2014/06/30,2018/09/30,17,11708.78114,0 170 | 2014/06/30,2018/12/31,18,11364.81895,0 171 | 2014/06/30,2019/03/31,19,11469.4945,0 172 | 2014/06/30,2019/06/30,20,10940.32727,0 173 | 2014/09/30,2015/03/31,2,6178.124471,0 174 | 2014/09/30,2015/06/30,3,8651.020424,0 175 | 2014/09/30,2015/09/30,4,10214.28305,0 176 | 2014/09/30,2015/12/31,5,11282.7084,0 177 | 2014/09/30,2016/03/31,6,11203.48095,0 178 | 2014/09/30,2016/06/30,7,11551.5818,0 179 | 2014/09/30,2016/09/30,8,12697.20014,0 180 | 2014/09/30,2016/12/31,9,12468.06252,0 181 | 2014/09/30,2017/03/31,10,12828.07945,0 182 | 2014/09/30,2017/06/30,11,14162.85548,0 183 | 2014/09/30,2017/09/30,12,13961.60732,0 184 | 2014/09/30,2017/12/31,13,14113.86584,0 185 | 2014/09/30,2018/03/31,14,14931.72786,0 186 | 2014/09/30,2018/06/30,15,16580.93744,0 187 | 2014/09/30,2018/09/30,16,16279.29189,0 188 | 2014/09/30,2018/12/31,17,15667.74672,0 189 | 2014/09/30,2019/03/31,18,15625.05807,0 190 | 2014/09/30,2019/06/30,19,17347.31035,0 191 | 2014/09/30,2019/09/30,20,17165.33718,0 192 | 2014/12/31,2015/03/31,1,4341.617273,0 193 | 2014/12/31,2015/06/30,2,4786.546492,0 194 | 2014/12/31,2015/09/30,3,6309.515306,0 195 | 2014/12/31,2015/12/31,4,7942.635259,0 196 | 2014/12/31,2016/03/31,5,8481.951506,0 197 | 2014/12/31,2016/06/30,6,8669.772274,0 198 | 2014/12/31,2016/09/30,7,8747.348902,0 199 | 2014/12/31,2016/12/31,8,9149.728974,0 200 | 2014/12/31,2017/03/31,9,9373.867648,0 201 | 2014/12/31,2017/06/30,10,9823.168036,0 202 | 2014/12/31,2017/09/30,11,10711.74767,0 203 | 2014/12/31,2017/12/31,12,11521.55326,0 204 | 2014/12/31,2018/03/31,13,11241.58918,0 205 | 2014/12/31,2018/06/30,14,12279.20709,0 206 | 2014/12/31,2018/09/30,15,13806.30294,0 207 | 2014/12/31,2018/12/31,16,13720.93726,0 208 | 2014/12/31,2019/03/31,17,13857.64092,0 209 | 2014/12/31,2019/06/30,18,14243.54773,0 210 | 2014/12/31,2019/09/30,19,16558.00043,0 211 | 2014/12/31,2019/12/31,20,16405.61403,0 212 | -------------------------------------------------------------------------------- /src/tryangle/utils/data/sme_test.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 2010/03/31,2015/03/31,20,24096.95571,0 3 | 2010/06/30,2015/03/31,19,22592.40107,0 4 | 2010/06/30,2015/06/30,20,22589.88616,0 5 | 2010/09/30,2015/03/31,18,17754.29048,0 6 | 2010/09/30,2015/06/30,19,17754.29048,0 7 | 2010/09/30,2015/09/30,20,17754.29048,0 8 | 2010/12/31,2015/03/31,17,23829.94857,0 9 | 2010/12/31,2015/06/30,18,23829.94857,0 10 | 2010/12/31,2015/09/30,19,23828.50131,0 11 | 2010/12/31,2015/12/31,20,23774.35964,0 12 | 2011/03/31,2015/03/31,16,26000.57381,0 13 | 2011/03/31,2015/06/30,17,26000.57381,0 14 | 2011/03/31,2015/09/30,18,26000.57381,0 15 | 2011/03/31,2015/12/31,19,26000.57381,0 16 | 2011/03/31,2016/03/31,20,26000.57381,0 17 | 2011/06/30,2015/03/31,15,22062.42012,0 18 | 2011/06/30,2015/06/30,16,22062.42012,0 19 | 2011/06/30,2015/09/30,17,22062.42012,0 20 | 2011/06/30,2015/12/31,18,22062.42012,0 21 | 2011/06/30,2016/03/31,19,22062.42012,0 22 | 2011/06/30,2016/06/30,20,22062.42012,0 23 | 2011/09/30,2015/03/31,14,25940.09743,0 24 | 2011/09/30,2015/06/30,15,25940.09743,0 25 | 2011/09/30,2015/09/30,16,25940.09743,0 26 | 2011/09/30,2015/12/31,17,25940.09743,0 27 | 2011/09/30,2016/03/31,18,25927.68897,0 28 | 2011/09/30,2016/06/30,19,25921.44916,0 29 | 2011/09/30,2016/09/30,20,25931.95957,0 30 | 2011/12/31,2015/03/31,13,32463.95455,0 31 | 2011/12/31,2015/06/30,14,32463.95455,0 32 | 2011/12/31,2015/09/30,15,32463.95455,0 33 | 2011/12/31,2015/12/31,16,32463.95455,0 34 | 2011/12/31,2016/03/31,17,32463.95455,0 35 | 2011/12/31,2016/06/30,18,32463.95455,0 36 | 2011/12/31,2016/09/30,19,32463.95455,0 37 | 2011/12/31,2016/12/31,20,32463.95455,0 38 | 2012/03/31,2015/03/31,12,29765.69719,0 39 | 2012/03/31,2015/06/30,13,29764.65326,0 40 | 2012/03/31,2015/09/30,14,29763.63307,0 41 | 2012/03/31,2015/12/31,15,29763.63307,0 42 | 2012/03/31,2016/03/31,16,29763.63307,0 43 | 2012/03/31,2016/06/30,17,29763.63307,0 44 | 2012/03/31,2016/09/30,18,29759.90816,0 45 | 2012/03/31,2016/12/31,19,29759.90816,0 46 | 2012/03/31,2017/03/31,20,29759.90816,0 47 | 2012/06/30,2015/03/31,11,27184.00337,0 48 | 2012/06/30,2015/06/30,12,27184.00337,0 49 | 2012/06/30,2015/09/30,13,27184.00337,0 50 | 2012/06/30,2015/12/31,14,27043.73802,0 51 | 2012/06/30,2016/03/31,15,27043.73802,0 52 | 2012/06/30,2016/06/30,16,27043.73802,0 53 | 2012/06/30,2016/09/30,17,27043.73802,0 54 | 2012/06/30,2016/12/31,18,27043.73802,0 55 | 2012/06/30,2017/03/31,19,27043.73802,0 56 | 2012/06/30,2017/06/30,20,27043.73802,0 57 | 2012/09/30,2015/03/31,10,32479.8032,0 58 | 2012/09/30,2015/06/30,11,32317.23586,0 59 | 2012/09/30,2015/09/30,12,32441.72372,0 60 | 2012/09/30,2015/12/31,13,32413.25309,0 61 | 2012/09/30,2016/03/31,14,32454.13218,0 62 | 2012/09/30,2016/06/30,15,32454.13218,0 63 | 2012/09/30,2016/09/30,16,32560.84962,0 64 | 2012/09/30,2016/12/31,17,32564.50335,0 65 | 2012/09/30,2017/03/31,18,32564.50335,0 66 | 2012/09/30,2017/06/30,19,32560.56492,0 67 | 2012/09/30,2017/09/30,20,32560.56492,0 68 | 2012/12/31,2015/03/31,9,41486.03907,0 69 | 2012/12/31,2015/06/30,10,41475.59983,0 70 | 2012/12/31,2015/09/30,11,41551.30801,0 71 | 2012/12/31,2015/12/31,12,41551.30801,0 72 | 2012/12/31,2016/03/31,13,41551.30801,0 73 | 2012/12/31,2016/06/30,14,41551.30801,0 74 | 2012/12/31,2016/09/30,15,41583.40865,0 75 | 2012/12/31,2016/12/31,16,41583.40865,0 76 | 2012/12/31,2017/03/31,17,41583.40865,0 77 | 2012/12/31,2017/06/30,18,41255.9963,0 78 | 2012/12/31,2017/09/30,19,41214.38172,0 79 | 2012/12/31,2017/12/31,20,41214.38172,0 80 | 2013/03/31,2015/03/31,8,38508.0814,0 81 | 2013/03/31,2015/06/30,9,38516.29044,0 82 | 2013/03/31,2015/09/30,10,38526.65849,0 83 | 2013/03/31,2015/12/31,11,38510.71494,0 84 | 2013/03/31,2016/03/31,12,38510.71494,0 85 | 2013/03/31,2016/06/30,13,38510.71494,0 86 | 2013/03/31,2016/09/30,14,38776.89169,0 87 | 2013/03/31,2016/12/31,15,38729.01356,0 88 | 2013/03/31,2017/03/31,16,38726.64101,0 89 | 2013/03/31,2017/06/30,17,38726.64101,0 90 | 2013/03/31,2017/09/30,18,38726.64101,0 91 | 2013/03/31,2017/12/31,19,38726.64101,0 92 | 2013/03/31,2018/03/31,20,38737.05652,0 93 | 2013/06/30,2015/03/31,7,26322.95634,0 94 | 2013/06/30,2015/06/30,8,26318.30614,0 95 | 2013/06/30,2015/09/30,9,26309.00573,0 96 | 2013/06/30,2015/12/31,10,26621.18629,0 97 | 2013/06/30,2016/03/31,11,26621.18629,0 98 | 2013/06/30,2016/06/30,12,26639.73965,0 99 | 2013/06/30,2016/09/30,13,26639.73965,0 100 | 2013/06/30,2016/12/31,14,26624.34178,0 101 | 2013/06/30,2017/03/31,15,26624.34178,0 102 | 2013/06/30,2017/06/30,16,26623.63002,0 103 | 2013/06/30,2017/09/30,17,26623.63002,0 104 | 2013/06/30,2017/12/31,18,26623.63002,0 105 | 2013/06/30,2018/03/31,19,26623.63002,0 106 | 2013/06/30,2018/06/30,20,26623.63002,0 107 | 2013/09/30,2015/03/31,6,27364.72075,0 108 | 2013/09/30,2015/06/30,7,27262.70096,0 109 | 2013/09/30,2015/09/30,8,27243.91034,0 110 | 2013/09/30,2015/12/31,9,27246.16426,0 111 | 2013/09/30,2016/03/31,10,27256.55605,0 112 | 2013/09/30,2016/06/30,11,27246.14054,0 113 | 2013/09/30,2016/09/30,12,27246.14054,0 114 | 2013/09/30,2016/12/31,13,27258.64389,0 115 | 2013/09/30,2017/03/31,14,27258.64389,0 116 | 2013/09/30,2017/06/30,15,27258.64389,0 117 | 2013/09/30,2017/09/30,16,27258.64389,0 118 | 2013/09/30,2017/12/31,17,27258.64389,0 119 | 2013/09/30,2018/03/31,18,27258.64389,0 120 | 2013/09/30,2018/06/30,19,27258.66762,0 121 | 2013/09/30,2018/09/30,20,27258.64389,0 122 | 2013/12/31,2015/03/31,5,45806.36363,0 123 | 2013/12/31,2015/06/30,6,44432.8451,0 124 | 2013/12/31,2015/09/30,7,44633.70546,0 125 | 2013/12/31,2015/12/31,8,44637.71508,0 126 | 2013/12/31,2016/03/31,9,44694.01577,0 127 | 2013/12/31,2016/06/30,10,44694.01577,0 128 | 2013/12/31,2016/09/30,11,44683.57653,0 129 | 2013/12/31,2016/12/31,12,44481.43499,0 130 | 2013/12/31,2017/03/31,13,44528.71998,0 131 | 2013/12/31,2017/06/30,14,44567.20279,0 132 | 2013/12/31,2017/09/30,15,44675.6522,0 133 | 2013/12/31,2017/12/31,16,44707.04108,0 134 | 2013/12/31,2018/03/31,17,44790.29398,0 135 | 2013/12/31,2018/06/30,18,44837.1519,0 136 | 2013/12/31,2018/09/30,19,44883.06081,0 137 | 2013/12/31,2018/12/31,20,44814.47029,0 138 | 2014/03/31,2015/03/31,4,37946.52177,0 139 | 2014/03/31,2015/06/30,5,37692.44505,0 140 | 2014/03/31,2015/09/30,6,37686.37131,0 141 | 2014/03/31,2015/12/31,7,37629.2165,0 142 | 2014/03/31,2016/03/31,8,37634.19886,0 143 | 2014/03/31,2016/06/30,9,37634.19886,0 144 | 2014/03/31,2016/09/30,10,37612.44255,0 145 | 2014/03/31,2016/12/31,11,37612.44255,0 146 | 2014/03/31,2017/03/31,12,37599.79684,0 147 | 2014/03/31,2017/06/30,13,37599.79684,0 148 | 2014/03/31,2017/09/30,14,37599.79684,0 149 | 2014/03/31,2017/12/31,15,37599.79684,0 150 | 2014/03/31,2018/03/31,16,37599.79684,0 151 | 2014/03/31,2018/06/30,17,37599.82057,0 152 | 2014/03/31,2018/09/30,18,37599.82057,0 153 | 2014/03/31,2018/12/31,19,37599.79684,0 154 | 2014/03/31,2019/03/31,20,37599.82057,0 155 | 2014/06/30,2015/03/31,3,38611.97551,0 156 | 2014/06/30,2015/06/30,4,37948.23001,0 157 | 2014/06/30,2015/09/30,5,38007.56757,0 158 | 2014/06/30,2015/12/31,6,38109.23148,0 159 | 2014/06/30,2016/03/31,7,38098.74479,0 160 | 2014/06/30,2016/06/30,8,38210.08871,0 161 | 2014/06/30,2016/09/30,9,38178.84219,0 162 | 2014/06/30,2016/12/31,10,38178.84219,0 163 | 2014/06/30,2017/03/31,11,38177.65591,0 164 | 2014/06/30,2017/06/30,12,38177.65591,0 165 | 2014/06/30,2017/09/30,13,38177.65591,0 166 | 2014/06/30,2017/12/31,14,38177.65591,0 167 | 2014/06/30,2018/03/31,15,38177.65591,0 168 | 2014/06/30,2018/06/30,16,38177.65591,0 169 | 2014/06/30,2018/09/30,17,38177.65591,0 170 | 2014/06/30,2018/12/31,18,38175.40199,0 171 | 2014/06/30,2019/03/31,19,38175.40199,0 172 | 2014/06/30,2019/06/30,20,38185.72259,0 173 | 2014/09/30,2015/03/31,2,35282.14447,0 174 | 2014/09/30,2015/06/30,3,34872.14355,0 175 | 2014/09/30,2015/09/30,4,35780.52301,0 176 | 2014/09/30,2015/12/31,5,35467.41716,0 177 | 2014/09/30,2016/03/31,6,35473.39599,0 178 | 2014/09/30,2016/06/30,7,35477.31071,0 179 | 2014/09/30,2016/09/30,8,35450.19242,0 180 | 2014/09/30,2016/12/31,9,35662.91555,0 181 | 2014/09/30,2017/03/31,10,35628.34744,0 182 | 2014/09/30,2017/06/30,11,35557.69281,0 183 | 2014/09/30,2017/09/30,12,35557.69281,0 184 | 2014/09/30,2017/12/31,13,35563.69537,0 185 | 2014/09/30,2018/03/31,14,35563.69537,0 186 | 2014/09/30,2018/06/30,15,35576.12755,0 187 | 2014/09/30,2018/09/30,16,35576.12755,0 188 | 2014/09/30,2018/12/31,17,35570.88421,0 189 | 2014/09/30,2019/03/31,18,35570.88421,0 190 | 2014/09/30,2019/06/30,19,35568.91499,0 191 | 2014/09/30,2019/09/30,20,35555.58124,0 192 | 2014/12/31,2015/03/31,1,35454.98498,0 193 | 2014/12/31,2015/06/30,2,36729.97137,0 194 | 2014/12/31,2015/09/30,3,37065.5453,0 195 | 2014/12/31,2015/12/31,4,36676.58892,0 196 | 2014/12/31,2016/03/31,5,36631.46296,0 197 | 2014/12/31,2016/06/30,6,36391.88253,0 198 | 2014/12/31,2016/09/30,7,36360.65973,0 199 | 2014/12/31,2016/12/31,8,36376.36603,0 200 | 2014/12/31,2017/03/31,9,36386.78154,0 201 | 2014/12/31,2017/06/30,10,36420.49552,0 202 | 2014/12/31,2017/09/30,11,36420.49552,0 203 | 2014/12/31,2017/12/31,12,36430.91103,0 204 | 2014/12/31,2018/03/31,13,36445.02772,0 205 | 2014/12/31,2018/06/30,14,36449.70165,0 206 | 2014/12/31,2018/09/30,15,36449.86773,0 207 | 2014/12/31,2018/12/31,16,36436.98477,0 208 | 2014/12/31,2019/03/31,17,36436.98477,0 209 | 2014/12/31,2019/06/30,18,36436.98477,0 210 | 2014/12/31,2019/09/30,19,36436.98477,0 211 | 2014/12/31,2019/12/31,20,36436.98477,0 212 | -------------------------------------------------------------------------------- /src/tryangle/ensemble/optimizers.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import numpy as np 6 | 7 | 8 | class SGD: 9 | """ 10 | Stochastic Gradient Descent optimizer with decay and momentum 11 | 12 | Parameters 13 | ---------- 14 | learning_rate : float, default=0.0001 15 | The initial learning rate used. It controls the step-size used 16 | in updating the weights and biases. 17 | 18 | decay : float, default=0.0 19 | The learning rate decay over epochs. 20 | 21 | momentum : float, default=0.0 22 | The value of momentum used. Must be larger than or equal to 0. 23 | """ 24 | 25 | def __init__(self, learning_rate=0.0001, decay=0.0, momentum=0.0): 26 | self.learning_rate = learning_rate 27 | self._learning_rate = learning_rate 28 | self.decay = decay 29 | self.momentum = momentum 30 | 31 | def reset(self, model): 32 | model.weight_momentums = np.zeros_like(model.initial_weight) 33 | model.bias_momentums = np.zeros_like(model.initial_bias) 34 | 35 | def pre_update_params(self, epoch): 36 | if self.decay: 37 | self._learning_rate = self.learning_rate * ( 38 | 1.0 / (1.0 + self.decay * epoch) 39 | ) 40 | 41 | def update_params(self, model, epoch): 42 | if self.momentum: 43 | if not hasattr(model, "weight_momentums"): 44 | self.reset(model) 45 | 46 | weight_updates = ( 47 | self.momentum * model.weight_momentums 48 | - self._learning_rate * model._w_grad 49 | ) 50 | model.weight_momentums = weight_updates 51 | 52 | bias_updates = ( 53 | self.momentum * model.bias_momentums 54 | - self._learning_rate * model._b_grad 55 | ) 56 | model.bias_momentums = bias_updates 57 | else: 58 | weight_updates = -self._learning_rate * model._w_grad 59 | bias_updates = -self._learning_rate * model._b_grad 60 | 61 | model.weights = model.weights + weight_updates 62 | model.biases = model.biases + bias_updates 63 | 64 | 65 | class AdaGrad: 66 | """ 67 | Adaptive Gradient Algorithm with decay 68 | 69 | Parameters 70 | ---------- 71 | learning_rate : float, default=0.0001 72 | The initial learning rate used. It controls the step-size used 73 | in updating the weights and biases. 74 | 75 | decay : float, default=0.0 76 | The learning rate decay over epochs. 77 | 78 | epsilon : float, default=1e-7 79 | A small constant for numerical stability. 80 | """ 81 | 82 | def __init__(self, learning_rate=0.0001, decay=0.0, epsilon=1e-7): 83 | self.learning_rate = learning_rate 84 | self._learning_rate = learning_rate 85 | self.decay = decay 86 | self.epsilon = epsilon 87 | 88 | def pre_update_params(self, epoch): 89 | if self.decay: 90 | self._learning_rate = self.learning_rate * ( 91 | 1.0 / (1.0 + self.decay * epoch) 92 | ) 93 | 94 | def update_params(self, model, epoch): 95 | if not hasattr(model, "weight_cache"): 96 | model.weight_cache = np.zeros_like(model.weights) 97 | model.bias_cache = np.zeros_like(model.biases) 98 | 99 | model.weight_cache += model._w_grad**2 100 | model.bias_cache += model._b_grad**2 101 | 102 | model.weights += ( 103 | -model.optimizer._learning_rate 104 | * model._w_grad 105 | / (np.sqrt(model.weight_cache) + self.epsilon) 106 | ) 107 | model.biases += ( 108 | -model.optimizer._learning_rate 109 | * model._w_grad 110 | / (np.sqrt(model.bias_cache) + self.epsilon) 111 | ) 112 | 113 | 114 | class RMSProp: 115 | """ 116 | RMSProp with decay 117 | 118 | Parameters 119 | ---------- 120 | learning_rate : float, default=0.0001 121 | The initial learning rate used. It controls the step-size used 122 | in updating the weights and biases. 123 | 124 | decay : float, default=0.0 125 | The learning rate decay over epochs. 126 | 127 | epsilon : float, default=1e-7 128 | A small constant for numerical stability. 129 | 130 | rho : float, default=0.9 131 | Discounting factor for the history/coming gradient. 132 | """ 133 | 134 | def __init__(self, learning_rate=0.0001, decay=0.0, epsilon=1e-7, rho=0.9): 135 | self.learning_rate = learning_rate 136 | self._learning_rate = learning_rate 137 | self.decay = decay 138 | self.epsilon = epsilon 139 | self.rho = rho 140 | 141 | def reset(self, model): 142 | model.weight_cache = np.zeros_like(model.weights) 143 | model.bias_cache = np.zeros_like(model.biases) 144 | 145 | def pre_update_params(self, epoch): 146 | if self.decay: 147 | self._learning_rate = self.learning_rate * ( 148 | 1.0 / (1.0 + self.decay * epoch) 149 | ) 150 | 151 | def update_params(self, model, epoch): 152 | if not hasattr(model, "weight_cache"): 153 | self.reset(model) 154 | 155 | model.weight_cache += ( 156 | self.rho * model.weight_cache + (1 - self.rho) * model._w_grad**2 157 | ) 158 | model.bias_cache += ( 159 | self.rho * model.bias_cache + (1 - self.rho) * model._b_grad**2 160 | ) 161 | 162 | model.weights += ( 163 | -model.optimizer._learning_rate 164 | * model._w_grad 165 | / (np.sqrt(model.weight_cache) + self.epsilon) 166 | ) 167 | model.biases += ( 168 | -model.optimizer._learning_rate 169 | * model._w_grad 170 | / (np.sqrt(model.bias_cache) + self.epsilon) 171 | ) 172 | 173 | 174 | class Adam: 175 | """ 176 | Adam optimizer with decay 177 | 178 | Parameters 179 | ---------- 180 | learning_rate : float, default=0.0001 181 | The initial learning rate used. It controls the step-size used 182 | in updating the weights and biases. 183 | 184 | decay : float, default=0.0 185 | The learning rate decay over epochs. 186 | 187 | epsilon : float, default=1e-7 188 | A small constant for numerical stability. 189 | 190 | beta_1 : float, default=0.9 191 | Exponential decay rate for the 1st moment estimates. 192 | 193 | beta_2 : float, default=0.999 194 | Exponential decay rate for the 2nd moment estimates. 195 | """ 196 | 197 | def __init__( 198 | self, learning_rate=0.0001, decay=0.0, epsilon=1e-7, beta_1=0.9, beta_2=0.999 199 | ): 200 | 201 | self.learning_rate = learning_rate 202 | self._learning_rate = learning_rate 203 | self.decay = decay 204 | self.epsilon = epsilon 205 | self.beta_1 = beta_1 206 | self.beta_2 = beta_2 207 | 208 | def reset(self, model): 209 | model.weight_momentums = np.zeros_like(model.weights) 210 | model.weight_cache = np.zeros_like(model.weights) 211 | model.bias_momentums = np.zeros_like(model.biases) 212 | model.bias_cache = np.zeros_like(model.biases) 213 | 214 | def pre_update_params(self, epoch): 215 | if self.decay: 216 | self._learning_rate = self.learning_rate * ( 217 | 1.0 / (1.0 + self.decay * epoch) 218 | ) 219 | 220 | def update_params(self, model, epoch): 221 | if not hasattr(model, "weight_cache"): 222 | self.reset(model) 223 | 224 | model.weight_momentums = ( 225 | self.beta_1 * model.weight_momentums + (1 - self.beta_1) * model._w_grad 226 | ) 227 | model.bias_momentums = ( 228 | self.beta_1 * model.bias_momentums + (1 - self.beta_1) * model._b_grad 229 | ) 230 | 231 | weight_momentums_corrected = model.weight_momentums / ( 232 | 1 - self.beta_1 ** (epoch + 1) 233 | ) 234 | bias_momentums_corrected = model.bias_momentums / ( 235 | 1 - self.beta_1 ** (epoch + 1) 236 | ) 237 | 238 | model.weight_cache += ( 239 | self.beta_2 * model.weight_cache + (1 - self.beta_2) * model._w_grad**2 240 | ) 241 | model.bias_cache += ( 242 | self.beta_2 * model.bias_cache + (1 - self.beta_2) * model._b_grad**2 243 | ) 244 | 245 | weight_cache_corrected = model.weight_cache / (1 - self.beta_2 ** (epoch + 1)) 246 | bias_cache_corrected = model.bias_cache / (1 - self.beta_2 ** (epoch + 1)) 247 | 248 | model.weights += ( 249 | -model.optimizer._learning_rate 250 | * weight_momentums_corrected 251 | / (np.sqrt(weight_cache_corrected) + self.epsilon) 252 | ) 253 | model.biases += ( 254 | -model.optimizer._learning_rate 255 | * bias_momentums_corrected 256 | / (np.sqrt(bias_cache_corrected) + self.epsilon) 257 | ) 258 | -------------------------------------------------------------------------------- /src/tryangle/utils/data/swiss_test.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 1979,1998,19,8051,0 3 | 1980,1998,18,9749,0 4 | 1980,1999,19,9749,0 5 | 1981,1998,17,12666,0 6 | 1981,1999,18,12711,0 7 | 1981,2000,19,12713,0 8 | 1982,1998,16,14141,0 9 | 1982,1999,17,14145,0 10 | 1982,2000,18,14166,0 11 | 1982,2001,19,14167,0 12 | 1983,1998,15,16619,0 13 | 1983,1999,16,16681,0 14 | 1983,2000,17,16681,0 15 | 1983,2001,18,16687,0 16 | 1983,2002,19,16711,0 17 | 1984,1998,14,17298,0 18 | 1984,1999,15,17307,0 19 | 1984,2000,16,17308,0 20 | 1984,2001,17,17308,0 21 | 1984,2002,18,17309,0 22 | 1984,2003,19,17310,0 23 | 1985,1998,13,16426,0 24 | 1985,1999,14,16480,0 25 | 1985,2000,15,16480,0 26 | 1985,2001,16,16480,0 27 | 1985,2002,17,16480,0 28 | 1985,2003,18,16482,0 29 | 1985,2004,19,16482,0 30 | 1986,1998,12,17706,0 31 | 1986,1999,13,17706,0 32 | 1986,2000,14,17712,0 33 | 1986,2001,15,17713,0 34 | 1986,2002,16,17718,0 35 | 1986,2003,17,17719,0 36 | 1986,2004,18,17719,0 37 | 1986,2005,19,17719,0 38 | 1987,1998,11,18689,0 39 | 1987,1999,12,18746,0 40 | 1987,2000,13,18772,0 41 | 1987,2001,14,18774,0 42 | 1987,2002,15,18804,0 43 | 1987,2003,16,18804,0 44 | 1987,2004,17,18804,0 45 | 1987,2005,18,18806,0 46 | 1987,2006,19,18806,0 47 | 1988,1998,10,20611,0 48 | 1988,1999,11,21250,0 49 | 1988,2000,12,21257,0 50 | 1988,2001,13,22505,0 51 | 1988,2002,14,22509,0 52 | 1988,2003,15,22516,0 53 | 1988,2004,16,22518,0 54 | 1988,2005,17,22522,0 55 | 1988,2006,18,22523,0 56 | 1988,2007,19,22527,0 57 | 1989,1998,9,20415,0 58 | 1989,1999,10,20510,0 59 | 1989,2000,11,20594,0 60 | 1989,2001,12,20657,0 61 | 1989,2002,13,20752,0 62 | 1989,2003,14,20823,0 63 | 1989,2004,15,20899,0 64 | 1989,2005,16,20983,0 65 | 1989,2006,17,21124,0 66 | 1989,2007,18,21622,0 67 | 1989,2008,19,21627,0 68 | 1990,1998,8,23888,0 69 | 1990,1999,9,24061,0 70 | 1990,2000,10,24096,0 71 | 1990,2001,11,24301,0 72 | 1990,2002,12,24356,0 73 | 1990,2003,13,24389,0 74 | 1990,2004,14,24391,0 75 | 1990,2005,15,24784,0 76 | 1990,2006,16,24784,0 77 | 1990,2007,17,24794,0 78 | 1990,2008,18,24894,0 79 | 1990,2009,19,24900,0 80 | 1991,1998,7,24410,0 81 | 1991,1999,8,24884,0 82 | 1991,2000,9,24896,0 83 | 1991,2001,10,24968,0 84 | 1991,2002,11,25031,0 85 | 1991,2003,12,25172,0 86 | 1991,2004,13,25459,0 87 | 1991,2005,14,25460,0 88 | 1991,2006,15,25470,0 89 | 1991,2007,16,25734,0 90 | 1991,2008,17,25774,0 91 | 1991,2009,18,25877,0 92 | 1991,2010,19,25883,0 93 | 1992,1998,6,26129,0 94 | 1992,1999,7,26149,0 95 | 1992,2000,8,26166,0 96 | 1992,2001,9,26231,0 97 | 1992,2002,10,26328,0 98 | 1992,2003,11,26743,0 99 | 1992,2004,12,27023,0 100 | 1992,2005,13,27048,0 101 | 1992,2006,14,27075,0 102 | 1992,2007,15,27168,0 103 | 1992,2008,16,27234,0 104 | 1992,2009,17,27276,0 105 | 1992,2010,18,27386,0 106 | 1992,2011,19,27392,0 107 | 1993,1998,5,27120,0 108 | 1993,1999,6,27164,0 109 | 1993,2000,7,27183,0 110 | 1993,2001,8,27250,0 111 | 1993,2002,9,27490,0 112 | 1993,2003,10,27497,0 113 | 1993,2004,11,27561,0 114 | 1993,2005,12,27565,0 115 | 1993,2006,13,27582,0 116 | 1993,2007,14,27706,0 117 | 1993,2008,15,27787,0 118 | 1993,2009,16,27855,0 119 | 1993,2010,17,27898,0 120 | 1993,2011,18,28010,0 121 | 1993,2012,19,28017,0 122 | 1994,1998,4,27568,0 123 | 1994,1999,5,27637,0 124 | 1994,2000,6,27805,0 125 | 1994,2001,7,28003,0 126 | 1994,2002,8,28223,0 127 | 1994,2003,9,28240,0 128 | 1994,2004,10,28245,0 129 | 1994,2005,11,28250,0 130 | 1994,2006,12,28257,0 131 | 1994,2007,13,28297,0 132 | 1994,2008,14,28347,0 133 | 1994,2009,15,28430,0 134 | 1994,2010,16,28499,0 135 | 1994,2011,17,28543,0 136 | 1994,2012,18,28658,0 137 | 1994,2013,19,28665,0 138 | 1995,1998,3,27043,0 139 | 1995,1999,4,27866,0 140 | 1995,2000,5,27882,0 141 | 1995,2001,6,27903,0 142 | 1995,2002,7,27933,0 143 | 1995,2003,8,28492,0 144 | 1995,2004,9,28545,0 145 | 1995,2005,10,28564,0 146 | 1995,2006,11,28686,0 147 | 1995,2007,12,28695,0 148 | 1995,2008,13,28897,0 149 | 1995,2009,14,28948,0 150 | 1995,2010,15,29033,0 151 | 1995,2011,16,29104,0 152 | 1995,2012,17,29149,0 153 | 1995,2013,18,29266,0 154 | 1995,2014,19,29273,0 155 | 1996,1998,2,23909,0 156 | 1996,1999,3,24690,0 157 | 1996,2000,4,26083,0 158 | 1996,2001,5,26525,0 159 | 1996,2002,6,26567,0 160 | 1996,2003,7,26640,0 161 | 1996,2004,8,26695,0 162 | 1996,2005,9,26801,0 163 | 1996,2006,10,26814,0 164 | 1996,2007,11,27018,0 165 | 1996,2008,12,27078,0 166 | 1996,2009,13,27269,0 167 | 1996,2010,14,27317,0 168 | 1996,2011,15,27397,0 169 | 1996,2012,16,27463,0 170 | 1996,2013,17,27506,0 171 | 1996,2014,18,27616,0 172 | 1996,2015,19,27623,0 173 | 1997,1998,1,26918,0 174 | 1997,1999,2,28256,0 175 | 1997,2000,3,28569,0 176 | 1997,2001,4,28964,0 177 | 1997,2002,5,29268,0 178 | 1997,2003,6,29344,0 179 | 1997,2004,7,29393,0 180 | 1997,2005,8,30159,0 181 | 1997,2006,9,30936,0 182 | 1997,2007,10,30966,0 183 | 1997,2008,11,31122,0 184 | 1997,2009,12,31190,0 185 | 1997,2010,13,31410,0 186 | 1997,2011,14,31466,0 187 | 1997,2012,15,31558,0 188 | 1997,2013,16,31635,0 189 | 1997,2014,17,31684,0 190 | 1997,2015,18,31811,0 191 | 1997,2016,19,31819,0 192 | 1998,1998,0,17655,0 193 | 1998,1999,1,26241,0 194 | 1998,2000,2,27369,0 195 | 1998,2001,3,28063,0 196 | 1998,2002,4,28346,0 197 | 1998,2003,5,28780,0 198 | 1998,2004,6,29024,0 199 | 1998,2005,7,29180,0 200 | 1998,2006,8,29250,0 201 | 1998,2007,9,29575,0 202 | 1998,2008,10,29660,0 203 | 1998,2009,11,29809,0 204 | 1998,2010,12,29875,0 205 | 1998,2011,13,30085,0 206 | 1998,2012,14,30138,0 207 | 1998,2013,15,30227,0 208 | 1998,2014,16,30300,0 209 | 1998,2015,17,30347,0 210 | 1998,2016,18,30469,0 211 | 1998,2017,19,30476,0 212 | 1999,1999,0,16789,0 213 | 1999,2000,1,25547,0 214 | 1999,2001,2,27099,0 215 | 1999,2002,3,27801,0 216 | 1999,2003,4,27919,0 217 | 1999,2004,5,28052,0 218 | 1999,2005,6,30020,0 219 | 1999,2006,7,30035,0 220 | 1999,2007,8,30456,0 221 | 1999,2008,9,30663,0 222 | 1999,2009,10,30750,0 223 | 1999,2010,11,30905,0 224 | 1999,2011,12,30973,0 225 | 1999,2012,13,31192,0 226 | 1999,2013,14,31247,0 227 | 1999,2014,15,31338,0 228 | 1999,2015,16,31415,0 229 | 1999,2016,17,31463,0 230 | 1999,2017,18,31590,0 231 | 1999,2018,19,31597,0 232 | 2000,2000,0,15538,0 233 | 2000,2001,1,23830,0 234 | 2000,2002,2,25202,0 235 | 2000,2003,3,26462,0 236 | 2000,2004,4,27056,0 237 | 2000,2005,5,27480,0 238 | 2000,2006,6,27564,0 239 | 2000,2007,7,27612,0 240 | 2000,2008,8,27873,0 241 | 2000,2009,9,28062,0 242 | 2000,2010,10,28143,0 243 | 2000,2011,11,28284,0 244 | 2000,2012,12,28347,0 245 | 2000,2013,13,28546,0 246 | 2000,2014,14,28597,0 247 | 2000,2015,15,28681,0 248 | 2000,2016,16,28751,0 249 | 2000,2017,17,28795,0 250 | 2000,2018,18,28911,0 251 | 2000,2019,19,28917,0 252 | 2001,2001,0,15113,0 253 | 2001,2002,1,23405,0 254 | 2001,2003,2,26822,0 255 | 2001,2004,3,27711,0 256 | 2001,2005,4,28080,0 257 | 2001,2006,5,29203,0 258 | 2001,2007,6,29647,0 259 | 2001,2008,7,29751,0 260 | 2001,2009,8,30032,0 261 | 2001,2010,9,30236,0 262 | 2001,2011,10,30323,0 263 | 2001,2012,11,30475,0 264 | 2001,2013,12,30542,0 265 | 2001,2014,13,30758,0 266 | 2001,2015,14,30812,0 267 | 2001,2016,15,30903,0 268 | 2001,2017,16,30978,0 269 | 2001,2018,17,31025,0 270 | 2001,2019,18,31150,0 271 | 2001,2020,19,31157,0 272 | 2002,2002,0,14543,0 273 | 2002,2003,1,22674,0 274 | 2002,2004,2,23603,0 275 | 2002,2005,3,24159,0 276 | 2002,2006,4,24242,0 277 | 2002,2007,5,24425,0 278 | 2002,2008,6,24767,0 279 | 2002,2009,7,24854,0 280 | 2002,2010,8,25089,0 281 | 2002,2011,9,25260,0 282 | 2002,2012,10,25332,0 283 | 2002,2013,11,25459,0 284 | 2002,2014,12,25515,0 285 | 2002,2015,13,25695,0 286 | 2002,2016,14,25741,0 287 | 2002,2017,15,25816,0 288 | 2002,2018,16,25879,0 289 | 2002,2019,17,25919,0 290 | 2002,2020,18,26023,0 291 | 2002,2021,19,26029,0 292 | 2003,2003,0,14590,0 293 | 2003,2004,1,22337,0 294 | 2003,2005,2,23442,0 295 | 2003,2006,3,24031,0 296 | 2003,2007,4,24665,0 297 | 2003,2008,5,24942,0 298 | 2003,2009,6,25292,0 299 | 2003,2010,7,25380,0 300 | 2003,2011,8,25621,0 301 | 2003,2012,9,25794,0 302 | 2003,2013,10,25868,0 303 | 2003,2014,11,25998,0 304 | 2003,2015,12,26056,0 305 | 2003,2016,13,26239,0 306 | 2003,2017,14,26286,0 307 | 2003,2018,15,26363,0 308 | 2003,2019,16,26427,0 309 | 2003,2020,17,26468,0 310 | 2003,2021,18,26574,0 311 | 2003,2022,19,26580,0 312 | 2004,2004,0,13976,0 313 | 2004,2005,1,21527,0 314 | 2004,2006,2,22615,0 315 | 2004,2007,3,23242,0 316 | 2004,2008,4,23653,0 317 | 2004,2009,5,23918,0 318 | 2004,2010,6,24254,0 319 | 2004,2011,7,24339,0 320 | 2004,2012,8,24569,0 321 | 2004,2013,9,24736,0 322 | 2004,2014,10,24806,0 323 | 2004,2015,11,24931,0 324 | 2004,2016,12,24986,0 325 | 2004,2017,13,25162,0 326 | 2004,2018,14,25207,0 327 | 2004,2019,15,25281,0 328 | 2004,2020,16,25342,0 329 | 2004,2021,17,25381,0 330 | 2004,2022,18,25483,0 331 | 2004,2023,19,25489,0 332 | 2005,2005,0,12932,0 333 | 2005,2006,1,20118,0 334 | 2005,2007,2,21309,0 335 | 2005,2008,3,21824,0 336 | 2005,2009,4,22209,0 337 | 2005,2010,5,22459,0 338 | 2005,2011,6,22774,0 339 | 2005,2012,7,22853,0 340 | 2005,2013,8,23070,0 341 | 2005,2014,9,23226,0 342 | 2005,2015,10,23293,0 343 | 2005,2016,11,23410,0 344 | 2005,2017,12,23462,0 345 | 2005,2018,13,23627,0 346 | 2005,2019,14,23669,0 347 | 2005,2020,15,23738,0 348 | 2005,2021,16,23796,0 349 | 2005,2022,17,23832,0 350 | 2005,2023,18,23928,0 351 | 2005,2024,19,23934,0 352 | 2006,2006,0,12538,0 353 | 2006,2007,1,20357,0 354 | 2006,2008,2,21435,0 355 | 2006,2009,3,21953,0 356 | 2006,2010,4,22341,0 357 | 2006,2011,5,22592,0 358 | 2006,2012,6,22909,0 359 | 2006,2013,7,22989,0 360 | 2006,2014,8,23206,0 361 | 2006,2015,9,23364,0 362 | 2006,2016,10,23431,0 363 | 2006,2017,11,23548,0 364 | 2006,2018,12,23600,0 365 | 2006,2019,13,23767,0 366 | 2006,2020,14,23809,0 367 | 2006,2021,15,23879,0 368 | 2006,2022,16,23937,0 369 | 2006,2023,17,23974,0 370 | 2006,2024,18,24070,0 371 | 2006,2025,19,24076,0 372 | 2007,2007,0,12888,0 373 | 2007,2008,1,19413,0 374 | 2007,2009,2,20441,0 375 | 2007,2010,3,20935,0 376 | 2007,2011,4,21304,0 377 | 2007,2012,5,21544,0 378 | 2007,2013,6,21846,0 379 | 2007,2014,7,21922,0 380 | 2007,2015,8,22130,0 381 | 2007,2016,9,22280,0 382 | 2007,2017,10,22344,0 383 | 2007,2018,11,22456,0 384 | 2007,2019,12,22506,0 385 | 2007,2020,13,22664,0 386 | 2007,2021,14,22704,0 387 | 2007,2022,15,22771,0 388 | 2007,2023,16,22826,0 389 | 2007,2024,17,22861,0 390 | 2007,2025,18,22953,0 391 | 2007,2026,19,22959,0 392 | -------------------------------------------------------------------------------- /src/tryangle/utils/data/cas_train.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 2010/03/31,2010/03/31,0,2013.946441,25728.2402 3 | 2010/03/31,2010/06/30,1,3924.798392,25728.2402 4 | 2010/03/31,2010/09/30,2,6027.319135,25728.2402 5 | 2010/03/31,2010/12/31,3,6476.875283,25728.2402 6 | 2010/03/31,2011/03/31,4,5624.078779,25728.2402 7 | 2010/03/31,2011/06/30,5,5159.316543,25728.2402 8 | 2010/03/31,2011/09/30,6,5213.851529,25728.2402 9 | 2010/03/31,2011/12/31,7,6240.692643,25728.2402 10 | 2010/03/31,2012/03/31,8,6705.35025,25728.2402 11 | 2010/03/31,2012/06/30,9,6716.243297,25728.2402 12 | 2010/03/31,2012/09/30,10,7373.267224,25728.2402 13 | 2010/03/31,2012/12/31,11,7695.745579,25728.2402 14 | 2010/03/31,2013/03/31,12,9011.246614,25728.2402 15 | 2010/03/31,2013/06/30,13,9229.502811,25728.2402 16 | 2010/03/31,2013/09/30,14,8408.513538,25728.2402 17 | 2010/03/31,2013/12/31,15,8448.179574,25728.2402 18 | 2010/03/31,2014/03/31,16,8824.216376,25728.2402 19 | 2010/03/31,2014/06/30,17,9202.496891,25728.2402 20 | 2010/03/31,2014/09/30,18,9388.457588,25728.2402 21 | 2010/03/31,2014/12/31,19,9349.686712,25728.2402 22 | 2010/06/30,2010/06/30,0,2531.220834,25975.3502 23 | 2010/06/30,2010/09/30,1,4102.412015,25975.3502 24 | 2010/06/30,2010/12/31,2,3674.700088,25975.3502 25 | 2010/06/30,2011/03/31,3,3868.18245,25975.3502 26 | 2010/06/30,2011/06/30,4,4796.172364,25975.3502 27 | 2010/06/30,2011/09/30,5,6866.351106,25975.3502 28 | 2010/06/30,2011/12/31,6,6072.077117,25975.3502 29 | 2010/06/30,2012/03/31,7,6013.984744,25975.3502 30 | 2010/06/30,2012/06/30,8,5986.455679,25975.3502 31 | 2010/06/30,2012/09/30,9,5787.881369,25975.3502 32 | 2010/06/30,2012/12/31,10,5951.207315,25975.3502 33 | 2010/06/30,2013/03/31,11,5957.566436,25975.3502 34 | 2010/06/30,2013/06/30,12,6047.884556,25975.3502 35 | 2010/06/30,2013/09/30,13,6064.741458,25975.3502 36 | 2010/06/30,2013/12/31,14,5876.618428,25975.3502 37 | 2010/06/30,2014/03/31,15,5969.354642,25975.3502 38 | 2010/06/30,2014/06/30,16,5986.537057,25975.3502 39 | 2010/06/30,2014/09/30,17,5997.383602,25975.3502 40 | 2010/06/30,2014/12/31,18,5766.676548,25975.3502 41 | 2010/09/30,2010/09/30,0,2373.056588,24954.4902 42 | 2010/09/30,2010/12/31,1,4426.390053,24954.4902 43 | 2010/09/30,2011/03/31,2,7274.148638,24954.4902 44 | 2010/09/30,2011/06/30,3,6513.62333,24954.4902 45 | 2010/09/30,2011/09/30,4,6699.130635,24954.4902 46 | 2010/09/30,2011/12/31,5,7062.867711,24954.4902 47 | 2010/09/30,2012/03/31,6,7602.893111,24954.4902 48 | 2010/09/30,2012/06/30,7,7727.29705,24954.4902 49 | 2010/09/30,2012/09/30,8,7130.492953,24954.4902 50 | 2010/09/30,2012/12/31,9,7655.498271,24954.4902 51 | 2010/09/30,2013/03/31,10,7948.796747,24954.4902 52 | 2010/09/30,2013/06/30,11,8586.568929,24954.4902 53 | 2010/09/30,2013/09/30,12,9113.050679,24954.4902 54 | 2010/09/30,2013/12/31,13,7730.296416,24954.4902 55 | 2010/09/30,2014/03/31,14,7925.092455,24954.4902 56 | 2010/09/30,2014/06/30,15,8275.576519,24954.4902 57 | 2010/09/30,2014/09/30,16,8179.631681,24954.4902 58 | 2010/09/30,2014/12/31,17,7820.881922,24954.4902 59 | 2010/12/31,2010/12/31,0,3664.585946,24478.1902 60 | 2010/12/31,2011/03/31,1,6028.330549,24478.1902 61 | 2010/12/31,2011/06/30,2,5679.334543,24478.1902 62 | 2010/12/31,2011/09/30,3,5792.775683,24478.1902 63 | 2010/12/31,2011/12/31,4,5157.665729,24478.1902 64 | 2010/12/31,2012/03/31,5,5202.586468,24478.1902 65 | 2010/12/31,2012/06/30,6,4824.10832,24478.1902 66 | 2010/12/31,2012/09/30,7,4749.066041,24478.1902 67 | 2010/12/31,2012/12/31,8,5152.469153,24478.1902 68 | 2010/12/31,2013/03/31,9,5240.392431,24478.1902 69 | 2010/12/31,2013/06/30,10,5260.829972,24478.1902 70 | 2010/12/31,2013/09/30,11,5360.622834,24478.1902 71 | 2010/12/31,2013/12/31,12,5261.911138,24478.1902 72 | 2010/12/31,2014/03/31,13,5605.582689,24478.1902 73 | 2010/12/31,2014/06/30,14,5472.92468,24478.1902 74 | 2010/12/31,2014/09/30,15,5358.541878,24478.1902 75 | 2010/12/31,2014/12/31,16,6050.686289,24478.1902 76 | 2011/03/31,2011/03/31,0,3685.244371,23899.4402 77 | 2011/03/31,2011/06/30,1,6009.229935,23899.4402 78 | 2011/03/31,2011/09/30,2,6655.209685,23899.4402 79 | 2011/03/31,2011/12/31,3,5535.06271,23899.4402 80 | 2011/03/31,2012/03/31,4,6291.728368,23899.4402 81 | 2011/03/31,2012/06/30,5,6971.88694,23899.4402 82 | 2011/03/31,2012/09/30,6,6792.68063,23899.4402 83 | 2011/03/31,2012/12/31,7,6362.015838,23899.4402 84 | 2011/03/31,2013/03/31,8,6510.12407,23899.4402 85 | 2011/03/31,2013/06/30,9,6456.658626,23899.4402 86 | 2011/03/31,2013/09/30,10,6734.030235,23899.4402 87 | 2011/03/31,2013/12/31,11,6836.148187,23899.4402 88 | 2011/03/31,2014/03/31,12,7816.882767,23899.4402 89 | 2011/03/31,2014/06/30,13,8117.493651,23899.4402 90 | 2011/03/31,2014/09/30,14,8601.71689,23899.4402 91 | 2011/03/31,2014/12/31,15,8508.050641,23899.4402 92 | 2011/06/30,2011/06/30,0,5623.509132,21730.2502 93 | 2011/06/30,2011/09/30,1,9330.190833,21730.2502 94 | 2011/06/30,2011/12/31,2,8640.313384,21730.2502 95 | 2011/06/30,2012/03/31,3,7675.807932,21730.2502 96 | 2011/06/30,2012/06/30,4,7066.06471,21730.2502 97 | 2011/06/30,2012/09/30,5,6535.025784,21730.2502 98 | 2011/06/30,2012/12/31,6,7004.298695,21730.2502 99 | 2011/06/30,2013/03/31,7,6964.644285,21730.2502 100 | 2011/06/30,2013/06/30,8,7006.577283,21730.2502 101 | 2011/06/30,2013/09/30,9,7243.748086,21730.2502 102 | 2011/06/30,2013/12/31,10,7123.773443,21730.2502 103 | 2011/06/30,2014/03/31,11,7118.960507,21730.2502 104 | 2011/06/30,2014/06/30,12,7294.074659,21730.2502 105 | 2011/06/30,2014/09/30,13,7250.979116,21730.2502 106 | 2011/06/30,2014/12/31,14,6981.222177,21730.2502 107 | 2011/09/30,2011/09/30,0,6359.527992,15231.7602 108 | 2011/09/30,2011/12/31,1,8484.695112,15231.7602 109 | 2011/09/30,2012/03/31,2,9147.194626,15231.7602 110 | 2011/09/30,2012/06/30,3,6628.157263,15231.7602 111 | 2011/09/30,2012/09/30,4,6883.138256,15231.7602 112 | 2011/09/30,2012/12/31,5,6989.906388,15231.7602 113 | 2011/09/30,2013/03/31,6,7416.58365,15231.7602 114 | 2011/09/30,2013/06/30,7,7768.218634,15231.7602 115 | 2011/09/30,2013/09/30,8,8116.935629,15231.7602 116 | 2011/09/30,2013/12/31,9,7775.496165,15231.7602 117 | 2011/09/30,2014/03/31,10,7907.968167,15231.7602 118 | 2011/09/30,2014/06/30,11,7946.192646,15231.7602 119 | 2011/09/30,2014/09/30,12,7905.085056,15231.7602 120 | 2011/09/30,2014/12/31,13,7503.623394,15231.7602 121 | 2011/12/31,2011/12/31,0,3654.86707,11990.0202 122 | 2011/12/31,2012/03/31,1,4337.501863,11990.0202 123 | 2011/12/31,2012/06/30,2,3999.759293,11990.0202 124 | 2011/12/31,2012/09/30,3,4567.848528,11990.0202 125 | 2011/12/31,2012/12/31,4,6659.162338,11990.0202 126 | 2011/12/31,2013/03/31,5,6570.506657,11990.0202 127 | 2011/12/31,2013/06/30,6,6598.896005,11990.0202 128 | 2011/12/31,2013/09/30,7,6949.194062,11990.0202 129 | 2011/12/31,2013/12/31,8,7302.991379,11990.0202 130 | 2011/12/31,2014/03/31,9,7384.113769,11990.0202 131 | 2011/12/31,2014/06/30,10,8192.291796,11990.0202 132 | 2011/12/31,2014/09/30,11,8634.616914,11990.0202 133 | 2011/12/31,2014/12/31,12,8644.114906,11990.0202 134 | 2012/03/31,2012/03/31,0,1202.803924,11731.1402 135 | 2012/03/31,2012/06/30,1,2897.120245,11731.1402 136 | 2012/03/31,2012/09/30,2,3288.560769,11731.1402 137 | 2012/03/31,2012/12/31,3,2418.360967,11731.1402 138 | 2012/03/31,2013/03/31,4,2197.326288,11731.1402 139 | 2012/03/31,2013/06/30,5,3144.428441,11731.1402 140 | 2012/03/31,2013/09/30,6,3153.228906,11731.1402 141 | 2012/03/31,2013/12/31,7,3073.071429,11731.1402 142 | 2012/03/31,2014/03/31,8,3108.656931,11731.1402 143 | 2012/03/31,2014/06/30,9,2366.918351,11731.1402 144 | 2012/03/31,2014/09/30,10,1991.509322,11731.1402 145 | 2012/03/31,2014/12/31,11,2082.80398,11731.1402 146 | 2012/06/30,2012/06/30,0,1110.253717,11502.8702 147 | 2012/06/30,2012/09/30,1,2110.96082,11502.8702 148 | 2012/06/30,2012/12/31,2,3328.017546,11502.8702 149 | 2012/06/30,2013/03/31,3,5474.017472,11502.8702 150 | 2012/06/30,2013/06/30,4,5593.375966,11502.8702 151 | 2012/06/30,2013/09/30,5,5660.38506,11502.8702 152 | 2012/06/30,2013/12/31,6,4710.016155,11502.8702 153 | 2012/06/30,2014/03/31,7,4873.516482,11502.8702 154 | 2012/06/30,2014/06/30,8,4568.569306,11502.8702 155 | 2012/06/30,2014/09/30,9,4547.131976,11502.8702 156 | 2012/06/30,2014/12/31,10,4600.667173,11502.8702 157 | 2012/09/30,2012/09/30,0,775.7081453,13316.5402 158 | 2012/09/30,2012/12/31,1,3290.351088,13316.5402 159 | 2012/09/30,2013/03/31,2,6314.549126,13316.5402 160 | 2012/09/30,2013/06/30,3,7099.383249,13316.5402 161 | 2012/09/30,2013/09/30,4,7206.38389,13316.5402 162 | 2012/09/30,2013/12/31,5,6951.123887,13316.5402 163 | 2012/09/30,2014/03/31,6,6910.562692,13316.5402 164 | 2012/09/30,2014/06/30,7,6848.320033,13316.5402 165 | 2012/09/30,2014/09/30,8,6906.168272,13316.5402 166 | 2012/09/30,2014/12/31,9,6825.708533,13316.5402 167 | 2012/12/31,2012/12/31,0,1857.653892,14269.7402 168 | 2012/12/31,2013/03/31,1,3064.352342,14269.7402 169 | 2012/12/31,2013/06/30,2,3964.894568,14269.7402 170 | 2012/12/31,2013/09/30,3,3906.174421,14269.7402 171 | 2012/12/31,2013/12/31,4,4058.235306,14269.7402 172 | 2012/12/31,2014/03/31,5,4269.934748,14269.7402 173 | 2012/12/31,2014/06/30,6,4018.813405,14269.7402 174 | 2012/12/31,2014/09/30,7,3867.275665,14269.7402 175 | 2012/12/31,2014/12/31,8,5107.385658,14269.7402 176 | 2013/03/31,2013/03/31,0,1607.706719,15193.1202 177 | 2013/03/31,2013/06/30,1,4000.340565,15193.1202 178 | 2013/03/31,2013/09/30,2,4989.08508,15193.1202 179 | 2013/03/31,2013/12/31,3,4800.183144,15193.1202 180 | 2013/03/31,2014/03/31,4,4794.533176,15193.1202 181 | 2013/03/31,2014/06/30,5,5481.643767,15193.1202 182 | 2013/03/31,2014/09/30,6,4777.978535,15193.1202 183 | 2013/03/31,2014/12/31,7,4847.149962,15193.1202 184 | 2013/06/30,2013/06/30,0,3120.317258,15076.7802 185 | 2013/06/30,2013/09/30,1,3906.220923,15076.7802 186 | 2013/06/30,2013/12/31,2,7001.938728,15076.7802 187 | 2013/06/30,2014/03/31,3,9182.175605,15076.7802 188 | 2013/06/30,2014/06/30,4,9679.802988,15076.7802 189 | 2013/06/30,2014/09/30,5,7915.826971,15076.7802 190 | 2013/06/30,2014/12/31,6,10125.44136,15076.7802 191 | 2013/09/30,2013/09/30,0,1186.749178,18804.4802 192 | 2013/09/30,2013/12/31,1,1948.716041,18804.4802 193 | 2013/09/30,2014/03/31,2,3061.969125,18804.4802 194 | 2013/09/30,2014/06/30,3,4515.324745,18804.4802 195 | 2013/09/30,2014/09/30,4,4628.405496,18804.4802 196 | 2013/09/30,2014/12/31,5,4755.134526,18804.4802 197 | 2013/12/31,2013/12/31,0,508.1251647,17929.9502 198 | 2013/12/31,2014/03/31,1,1844.156745,17929.9502 199 | 2013/12/31,2014/06/30,2,4444.653635,17929.9502 200 | 2013/12/31,2014/09/30,3,6455.914597,17929.9502 201 | 2013/12/31,2014/12/31,4,7419.199377,17929.9502 202 | 2014/03/31,2014/03/31,0,631.9129553,18824.7102 203 | 2014/03/31,2014/06/30,1,1950.552862,18824.7102 204 | 2014/03/31,2014/09/30,2,2235.318258,18824.7102 205 | 2014/03/31,2014/12/31,3,4024.533126,18824.7102 206 | 2014/06/30,2014/06/30,0,575.9015377,20181.3402 207 | 2014/06/30,2014/09/30,1,3531.009527,20181.3402 208 | 2014/06/30,2014/12/31,2,8147.766322,20181.3402 209 | 2014/09/30,2014/09/30,0,1548.602932,20891.3602 210 | 2014/09/30,2014/12/31,1,4806.751524,20891.3602 211 | 2014/12/31,2014/12/31,0,1877.010266,23653.9902 212 | -------------------------------------------------------------------------------- /src/tryangle/utils/data/sme_train.csv: -------------------------------------------------------------------------------- 1 | origin,development,lag,claim,premium 2 | 2010/03/31,2010/03/31,0,15885.64381,51346.66641 3 | 2010/03/31,2010/06/30,1,25177.51136,51346.66641 4 | 2010/03/31,2010/09/30,2,26571.78973,51346.66641 5 | 2010/03/31,2010/12/31,3,25520.48766,51346.66641 6 | 2010/03/31,2011/03/31,4,25047.47172,51346.66641 7 | 2010/03/31,2011/06/30,5,25025.26462,51346.66641 8 | 2010/03/31,2011/09/30,6,24961.98862,51346.66641 9 | 2010/03/31,2011/12/31,7,24447.97496,51346.66641 10 | 2010/03/31,2012/03/31,8,24411.81725,51346.66641 11 | 2010/03/31,2012/06/30,9,24305.19471,51346.66641 12 | 2010/03/31,2012/09/30,10,24305.07608,51346.66641 13 | 2010/03/31,2012/12/31,11,24285.31271,51346.66641 14 | 2010/03/31,2013/03/31,12,24201.01589,51346.66641 15 | 2010/03/31,2013/06/30,13,24159.40131,51346.66641 16 | 2010/03/31,2013/09/30,14,24170.83702,51346.66641 17 | 2010/03/31,2013/12/31,15,24108.41514,51346.66641 18 | 2010/03/31,2014/03/31,16,24096.95571,51346.66641 19 | 2010/03/31,2014/06/30,17,24096.95571,51346.66641 20 | 2010/03/31,2014/09/30,18,24096.95571,51346.66641 21 | 2010/03/31,2014/12/31,19,24096.95571,51346.66641 22 | 2010/06/30,2010/06/30,0,18399.93339,53877.27641 23 | 2010/06/30,2010/09/30,1,24209.50963,53877.27641 24 | 2010/06/30,2010/12/31,2,22952.86308,53877.27641 25 | 2010/06/30,2011/03/31,3,22781.44611,53877.27641 26 | 2010/06/30,2011/06/30,4,22709.81873,53877.27641 27 | 2010/06/30,2011/09/30,5,22939.48188,53877.27641 28 | 2010/06/30,2011/12/31,6,22276.51933,53877.27641 29 | 2010/06/30,2012/03/31,7,22394.64875,53877.27641 30 | 2010/06/30,2012/06/30,8,22331.79982,53877.27641 31 | 2010/06/30,2012/09/30,9,22614.84542,53877.27641 32 | 2010/06/30,2012/12/31,10,22614.84542,53877.27641 33 | 2010/06/30,2013/03/31,11,22614.75052,53877.27641 34 | 2010/06/30,2013/06/30,12,22614.75052,53877.27641 35 | 2010/06/30,2013/09/30,13,22614.75052,53877.27641 36 | 2010/06/30,2013/12/31,14,22593.94322,53877.27641 37 | 2010/06/30,2014/03/31,15,22590.24204,53877.27641 38 | 2010/06/30,2014/06/30,16,22592.40107,53877.27641 39 | 2010/06/30,2014/09/30,17,22592.40107,53877.27641 40 | 2010/06/30,2014/12/31,18,22592.40107,53877.27641 41 | 2010/09/30,2010/09/30,0,15765.26046,54577.09641 42 | 2010/09/30,2010/12/31,1,18859.94774,54577.09641 43 | 2010/09/30,2011/03/31,2,17972.3044,54577.09641 44 | 2010/09/30,2011/06/30,3,18029.22195,54577.09641 45 | 2010/09/30,2011/09/30,4,18099.71051,54577.09641 46 | 2010/09/30,2011/12/31,5,17914.79371,54577.09641 47 | 2010/09/30,2012/03/31,6,17918.92195,54577.09641 48 | 2010/09/30,2012/06/30,7,17802.40586,54577.09641 49 | 2010/09/30,2012/09/30,8,17854.41223,54577.09641 50 | 2010/09/30,2012/12/31,9,17854.3885,54577.09641 51 | 2010/09/30,2013/03/31,10,17867.88833,54577.09641 52 | 2010/09/30,2013/06/30,11,17843.83064,54577.09641 53 | 2010/09/30,2013/09/30,12,17828.90728,54577.09641 54 | 2010/09/30,2013/12/31,13,17828.90728,54577.09641 55 | 2010/09/30,2014/03/31,14,17762.30971,54577.09641 56 | 2010/09/30,2014/06/30,15,17762.30971,54577.09641 57 | 2010/09/30,2014/09/30,16,17754.29048,54577.09641 58 | 2010/09/30,2014/12/31,17,17754.29048,54577.09641 59 | 2010/12/31,2010/12/31,0,18049.1514,55527.48641 60 | 2010/12/31,2011/03/31,1,24586.08129,55527.48641 61 | 2010/12/31,2011/06/30,2,24557.61065,55527.48641 62 | 2010/12/31,2011/09/30,3,24341.73203,55527.48641 63 | 2010/12/31,2011/12/31,4,23850.18645,55527.48641 64 | 2010/12/31,2012/03/31,5,23923.40344,55527.48641 65 | 2010/12/31,2012/06/30,6,23912.37107,55527.48641 66 | 2010/12/31,2012/09/30,7,23959.22899,55527.48641 67 | 2010/12/31,2012/12/31,8,23949.21682,55527.48641 68 | 2010/12/31,2013/03/31,9,23823.18679,55527.48641 69 | 2010/12/31,2013/06/30,10,23921.38677,55527.48641 70 | 2010/12/31,2013/09/30,11,23836.0223,55527.48641 71 | 2010/12/31,2013/12/31,12,23862.87961,55527.48641 72 | 2010/12/31,2014/03/31,13,23862.85588,55527.48641 73 | 2010/12/31,2014/06/30,14,23853.15214,55527.48641 74 | 2010/12/31,2014/09/30,15,23829.94857,55527.48641 75 | 2010/12/31,2014/12/31,16,23829.94857,55527.48641 76 | 2011/03/31,2011/03/31,0,22716.20089,56767.61641 77 | 2011/03/31,2011/06/30,1,28799.4986,56767.61641 78 | 2011/03/31,2011/09/30,2,28139.21703,56767.61641 79 | 2011/03/31,2011/12/31,3,26890.42363,56767.61641 80 | 2011/03/31,2012/03/31,4,27203.1736,56767.61641 81 | 2011/03/31,2012/06/30,5,27014.27091,56767.61641 82 | 2011/03/31,2012/09/30,6,26813.00722,56767.61641 83 | 2011/03/31,2012/12/31,7,26542.22772,56767.61641 84 | 2011/03/31,2013/03/31,8,26363.69308,56767.61641 85 | 2011/03/31,2013/06/30,9,26522.72533,56767.61641 86 | 2011/03/31,2013/09/30,10,26259.32447,56767.61641 87 | 2011/03/31,2013/12/31,11,26256.54858,56767.61641 88 | 2011/03/31,2014/03/31,12,26050.51605,56767.61641 89 | 2011/03/31,2014/06/30,13,26000.57381,56767.61641 90 | 2011/03/31,2014/09/30,14,26000.57381,56767.61641 91 | 2011/03/31,2014/12/31,15,26000.57381,56767.61641 92 | 2011/06/30,2011/06/30,0,17629.56535,57243.72641 93 | 2011/06/30,2011/09/30,1,24164.4074,57243.72641 94 | 2011/06/30,2011/12/31,2,23772.50905,57243.72641 95 | 2011/06/30,2012/03/31,3,23060.50582,57243.72641 96 | 2011/06/30,2012/06/30,4,22775.34865,57243.72641 97 | 2011/06/30,2012/09/30,5,22658.66648,57243.72641 98 | 2011/06/30,2012/12/31,6,22348.52632,57243.72641 99 | 2011/06/30,2013/03/31,7,22241.50044,57243.72641 100 | 2011/06/30,2013/06/30,8,22254.90537,57243.72641 101 | 2011/06/30,2013/09/30,9,22228.85473,57243.72641 102 | 2011/06/30,2013/12/31,10,22228.85473,57243.72641 103 | 2011/06/30,2014/03/31,11,22197.63193,57243.72641 104 | 2011/06/30,2014/06/30,12,22114.45021,57243.72641 105 | 2011/06/30,2014/09/30,13,22062.42012,57243.72641 106 | 2011/06/30,2014/12/31,14,22062.42012,57243.72641 107 | 2011/09/30,2011/09/30,0,20852.10953,58405.12641 108 | 2011/09/30,2011/12/31,1,28044.43353,58405.12641 109 | 2011/09/30,2012/03/31,2,27322.34695,58405.12641 110 | 2011/09/30,2012/06/30,3,27051.21156,58405.12641 111 | 2011/09/30,2012/09/30,4,26749.75495,58405.12641 112 | 2011/09/30,2012/12/31,5,26292.91982,58405.12641 113 | 2011/09/30,2013/03/31,6,26136.59229,58405.12641 114 | 2011/09/30,2013/06/30,7,26133.00973,58405.12641 115 | 2011/09/30,2013/09/30,8,26309.78867,58405.12641 116 | 2011/09/30,2013/12/31,9,26223.90225,58405.12641 117 | 2011/09/30,2014/03/31,10,25942.89704,58405.12641 118 | 2011/09/30,2014/06/30,11,25952.4347,58405.12641 119 | 2011/09/30,2014/09/30,12,25941.99547,58405.12641 120 | 2011/09/30,2014/12/31,13,25940.09743,58405.12641 121 | 2011/12/31,2011/12/31,0,21489.49596,59911.59641 122 | 2011/12/31,2012/03/31,1,32918.53575,59911.59641 123 | 2011/12/31,2012/06/30,2,32872.43704,59911.59641 124 | 2011/12/31,2012/09/30,3,32830.06324,59911.59641 125 | 2011/12/31,2012/12/31,4,32575.06122,59911.59641 126 | 2011/12/31,2013/03/31,5,32552.94902,59911.59641 127 | 2011/12/31,2013/06/30,6,32536.26997,59911.59641 128 | 2011/12/31,2013/09/30,7,32443.52686,59911.59641 129 | 2011/12/31,2013/12/31,8,32453.46786,59911.59641 130 | 2011/12/31,2014/03/31,9,32324.49587,59911.59641 131 | 2011/12/31,2014/06/30,10,32324.49587,59911.59641 132 | 2011/12/31,2014/09/30,11,32495.50951,59911.59641 133 | 2011/12/31,2014/12/31,12,32474.15653,59911.59641 134 | 2012/03/31,2012/03/31,0,18254.16372,60339.49641 135 | 2012/03/31,2012/06/30,1,29871.29953,60339.49641 136 | 2012/03/31,2012/09/30,2,30149.22042,60339.49641 137 | 2012/03/31,2012/12/31,3,29904.39665,60339.49641 138 | 2012/03/31,2013/03/31,4,30122.22077,60339.49641 139 | 2012/03/31,2013/06/30,5,30281.72752,60339.49641 140 | 2012/03/31,2013/09/30,6,30003.61683,60339.49641 141 | 2012/03/31,2013/12/31,7,30047.31926,60339.49641 142 | 2012/03/31,2014/03/31,8,29792.98155,60339.49641 143 | 2012/03/31,2014/06/30,9,29747.97422,60339.49641 144 | 2012/03/31,2014/09/30,10,29722.30319,60339.49641 145 | 2012/03/31,2014/12/31,11,29755.30541,60339.49641 146 | 2012/06/30,2012/06/30,0,21811.61752,61308.49641 147 | 2012/06/30,2012/09/30,1,29825.69906,61308.49641 148 | 2012/06/30,2012/12/31,2,28046.97216,61308.49641 149 | 2012/06/30,2013/03/31,3,27959.59103,61308.49641 150 | 2012/06/30,2013/06/30,4,28009.27229,61308.49641 151 | 2012/06/30,2013/09/30,5,27812.51645,61308.49641 152 | 2012/06/30,2013/12/31,6,27604.58588,61308.49641 153 | 2012/06/30,2014/03/31,7,27430.53538,61308.49641 154 | 2012/06/30,2014/06/30,8,27502.7559,61308.49641 155 | 2012/06/30,2014/09/30,9,27206.96969,61308.49641 156 | 2012/06/30,2014/12/31,10,27183.78984,61308.49641 157 | 2012/09/30,2012/09/30,0,25062.3239,60262.30641 158 | 2012/09/30,2012/12/31,1,35858.55629,60262.30641 159 | 2012/09/30,2013/03/31,2,36143.49993,60262.30641 160 | 2012/09/30,2013/06/30,3,35174.40683,60262.30641 161 | 2012/09/30,2013/09/30,4,34845.02526,60262.30641 162 | 2012/09/30,2013/12/31,5,34032.33087,60262.30641 163 | 2012/09/30,2014/03/31,6,33252.09301,60262.30641 164 | 2012/09/30,2014/06/30,7,33128.10338,60262.30641 165 | 2012/09/30,2014/09/30,8,32078.79425,60262.30641 166 | 2012/09/30,2014/12/31,9,32282.07462,60262.30641 167 | 2012/12/31,2012/12/31,0,27478.65076,60512.84641 168 | 2012/12/31,2013/03/31,1,41905.36413,60512.84641 169 | 2012/12/31,2013/06/30,2,42866.65153,60512.84641 170 | 2012/12/31,2013/09/30,3,42488.20556,60512.84641 171 | 2012/12/31,2013/12/31,4,42368.36789,60512.84641 172 | 2012/12/31,2014/03/31,5,41576.12491,60512.84641 173 | 2012/12/31,2014/06/30,6,41451.42351,60512.84641 174 | 2012/12/31,2014/09/30,7,40987.37582,60512.84641 175 | 2012/12/31,2014/12/31,8,41403.85382,60512.84641 176 | 2013/03/31,2013/03/31,0,26771.0842,62668.15641 177 | 2013/03/31,2013/06/30,1,40483.56414,62668.15641 178 | 2013/03/31,2013/09/30,2,39967.65244,62668.15641 179 | 2013/03/31,2013/12/31,3,40057.5722,62668.15641 180 | 2013/03/31,2014/03/31,4,40010.85663,62668.15641 181 | 2013/03/31,2014/06/30,5,38822.58706,62668.15641 182 | 2013/03/31,2014/09/30,6,38480.74959,62668.15641 183 | 2013/03/31,2014/12/31,7,38506.08846,62668.15641 184 | 2013/06/30,2013/06/30,0,20361.60787,63109.32641 185 | 2013/06/30,2013/09/30,1,26804.96426,63109.32641 186 | 2013/06/30,2013/12/31,2,26388.29646,63109.32641 187 | 2013/06/30,2014/03/31,3,26454.27717,63109.32641 188 | 2013/06/30,2014/06/30,4,26380.03998,63109.32641 189 | 2013/06/30,2014/09/30,5,26321.22438,63109.32641 190 | 2013/06/30,2014/12/31,6,26310.42926,63109.32641 191 | 2013/09/30,2013/09/30,0,19766.45289,62933.52641 192 | 2013/09/30,2013/12/31,1,29064.96359,62933.52641 193 | 2013/09/30,2014/03/31,2,28266.90785,62933.52641 194 | 2013/09/30,2014/06/30,3,27855.69692,62933.52641 195 | 2013/09/30,2014/09/30,4,27475.28173,62933.52641 196 | 2013/09/30,2014/12/31,5,27402.4918,62933.52641 197 | 2013/12/31,2013/12/31,0,27034.74604,63694.44641 198 | 2013/12/31,2014/03/31,1,43552.72275,63694.44641 199 | 2013/12/31,2014/06/30,2,45623.39232,63694.44641 200 | 2013/12/31,2014/09/30,3,45858.20392,63694.44641 201 | 2013/12/31,2014/12/31,4,45471.02695,63694.44641 202 | 2014/03/31,2014/03/31,0,19600.13691,64467.46641 203 | 2014/03/31,2014/06/30,1,35431.71023,64467.46641 204 | 2014/03/31,2014/09/30,2,37810.95408,64467.46641 205 | 2014/03/31,2014/12/31,3,38378.89588,64467.46641 206 | 2014/06/30,2014/06/30,0,22220.45589,66842.73641 207 | 2014/06/30,2014/09/30,1,35361.36403,66842.73641 208 | 2014/06/30,2014/12/31,2,38685.95172,66842.73641 209 | 2014/09/30,2014/09/30,0,22583.36164,68593.77641 210 | 2014/09/30,2014/12/31,1,34819.30679,68593.77641 211 | 2014/12/31,2014/12/31,0,25472.84679,69620.50641 212 | -------------------------------------------------------------------------------- /src/tryangle/ensemble/base.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at https://mozilla.org/MPL/2.0/. 4 | 5 | import numpy as np 6 | from chainladder.workflow.voting import _BaseTriangleEnsemble 7 | from sklearn.base import clone 8 | from sklearn.ensemble._base import _fit_single_estimator 9 | from sklearn.utils.validation import _deprecate_positional_args 10 | from tryangle.ensemble.optimizers import Adam 11 | from tryangle.metrics.base import get_expected 12 | from tryangle.ensemble.losses import LOSS_FUNCTIONS 13 | 14 | 15 | class AutoEnsemble(_BaseTriangleEnsemble): 16 | """Automated ensembling of chainladder methods 17 | 18 | `AutoEnsemble` uses a neural network to find optimal weights 19 | to ensemble multiple chainladder methods. 20 | 21 | Read more in the :ref:`User Guide ` 22 | 23 | .. versionadded:: 0.1.0 24 | 25 | Parameters 26 | ---------- 27 | estimators : list of (str, estimator) tuples 28 | Invoking the ``fit`` method on the ``AutoEnsemble`` will fit clones 29 | of those original estimators across the cv folds of the triangle and 30 | store the expected incremental claims for the next diagonal for each 31 | of the folds. 32 | 33 | cv : `TriangleSplit` cross-validation generator 34 | Determines the number of cross-validation folds 35 | over which to fit. Must be an instance of `TriangleSplit` 36 | 37 | Refer :ref:`User Guide ` 38 | 39 | max_iter : int, default=1000 40 | Maximum number of iterations (or epochs) used to train the neural 41 | network. Currently the optimizers use all iterations. 42 | 43 | optimizer : optimizer object, default=Adam() 44 | The optimization method to find optimal weights and biases. 45 | 46 | initial_weight : ndarray of shape (1, num_estimators), default=None 47 | Force the initial weights instead of using a random initialization 48 | 49 | initial_bias : ndarray of shape (1, num_estimators), default=None 50 | Force the initial biases instead of using a random initialization 51 | 52 | weight_function : 'linear', 'poly(n)', or None, default='linear' 53 | Specify a function to constrain the voting weights. 54 | ``poly(n)`` will fit an n-term polynomial: 55 | t^n * w + t^(n-1) * w + ... + t^(2) * w + t * w + b 56 | where t is the origin period, w is the weight, and b is the bias 57 | ``linear`` is equivalent to ``poly(1)`` 58 | ``None`` will not constrain the weights meaning each origin period 59 | will have its own vector of weights. 60 | 61 | random_state : int or None, default=None 62 | Specify the seed for random weight and bias initialization. 63 | 64 | n_jobs : int, default=None 65 | Number of jobs to run in parallel 66 | ``None`` means 1. 67 | ``-1`` means using all processors. 68 | Currently only the compilation step is run in parallel. Optimization 69 | is not. 70 | 71 | verbose : int, default=False 72 | Controls the verbosity: the higher, the more messages. 73 | 74 | dropout : float, default=False 75 | Randomly sets incremental claim amounts equal to 0 equivalently for 76 | actual and expected. That is, the same incremental claims set to 77 | zero for actual are set to zero for expected. Parameter is given as 78 | a proportion of number of incremental claims data points. 79 | 80 | broad_dropout : float, default=False 81 | Randomly sets entire folds to zero equivalently for actual and expected. 82 | Parameter is given as a proportion of the number of folds and rounded to 83 | the nearest integer. 84 | 85 | Attributes 86 | ---------- 87 | 88 | actual_ : ndarray 89 | The actual incremental claims for each fold. 90 | 91 | expected_ : ndarray 92 | The expected incremental claims for each estimator for each fold. 93 | 94 | weights_ : ndarray 95 | The optimal weights found to ensemble the estimators. 96 | 97 | Notes 98 | ----- 99 | 100 | ``AutoEnsemble`` is still experimental and may change with future versions. 101 | """ 102 | 103 | @_deprecate_positional_args 104 | def __init__( 105 | self, 106 | estimators, 107 | cv, 108 | max_iter=1000, 109 | optimizer=Adam(), 110 | initial_weight=None, 111 | initial_bias=None, 112 | weight_function="linear", 113 | loss="mse", 114 | random_state=None, 115 | n_jobs=None, 116 | verbose=False, 117 | dropout=False, 118 | broad_dropout=False, 119 | ): 120 | self.estimators = estimators 121 | self.cv = cv 122 | self.max_iter = max_iter 123 | self.optimizer = optimizer 124 | self.initial_weight = initial_weight 125 | self.initial_bias = initial_bias 126 | self.weight_function = weight_function 127 | self.loss = loss 128 | self.random_state = random_state 129 | self.n_jobs = n_jobs 130 | self.verbose = verbose 131 | self.dropout = dropout 132 | self.broad_dropout = broad_dropout 133 | 134 | def _log_message(self, name, idx, total): 135 | if self.verbose < 2: 136 | return None 137 | return "(%d of %d) Processing %s" % (idx, total, name) 138 | 139 | def initialize_weights(self): 140 | if self.weight_function is None: 141 | weight_dim = self.origin_dim 142 | elif self.weight_function == "linear": 143 | weight_dim = 1 144 | elif "poly" in self.weight_function: 145 | self.weight_polynomial = int( 146 | self.weight_function[ 147 | self.weight_function.find("(") + 1 : self.weight_function.find(")") 148 | ] 149 | ) 150 | weight_dim = 1 151 | else: 152 | raise Exception( 153 | "Unknown weight function provided. Options are None, linear, or poly(n)." 154 | ) 155 | 156 | if self.initial_weight is None: 157 | np.random.seed(self.random_state) 158 | self.weights = np.random.normal( 159 | 0, 160 | np.sqrt(2 / (2 * len(self.estimators))), 161 | size=(weight_dim, len(self.estimators)), 162 | ) 163 | else: 164 | self.weights = self.initial_weight 165 | if self.initial_bias is None: 166 | np.random.seed(self.random_state) 167 | self.biases = np.zeros((weight_dim, len(self.estimators))) 168 | else: 169 | self.biases = self.initial_bias 170 | 171 | def preprocess(self, X, y=None, sample_weight=None): 172 | """ 173 | In order to find optimal weights, the actual incremental claims 174 | and expected incremental claims for each estimator is required. 175 | This method also returns the `t` array. 176 | """ 177 | 178 | names, clfs = self._validate_estimators() 179 | 180 | actual = X.latest_diagonal.to_frame().fillna(0).to_numpy()[:-1] 181 | actual = actual[np.newaxis, ...] 182 | expected = np.array( 183 | [ 184 | get_expected( 185 | _fit_single_estimator( 186 | clone(clf), 187 | X, 188 | X, 189 | sample_weight=None, 190 | message_clsname=f"Preprocessing - {names[idx]}_expected", 191 | message=self._log_message(names[idx], idx + 1, len(clfs)), 192 | ), 193 | X, 194 | ) 195 | for idx, clf in enumerate(clfs) 196 | ] 197 | ) 198 | 199 | t = ( 200 | np.arange(1, actual.shape[1] + 1).reshape(-1, 1)[np.newaxis, ...] 201 | / actual.shape[1] 202 | ) 203 | 204 | return actual, expected, t 205 | 206 | def compile(self, X, y=None, sample_weight=None): 207 | """ 208 | Obtain the actual, expected, and t, arrays for each estimator 209 | for each fold and reshape for input to the neural network. 210 | """ 211 | # Fit individual estimators 212 | if self.verbose > 1: 213 | print("\n[Compiling]\n") 214 | 215 | names, clfs = self._validate_estimators() 216 | 217 | self.actual_ = [] 218 | self.expected_ = [] 219 | 220 | # Preprocessing for each fold 221 | for fold, (train, _) in enumerate(self.cv.split(X)): 222 | 223 | zeros_to_pad = self.cv.n_splits - fold 224 | 225 | fold_actual, fold_expected, _ = self.preprocess(X[train]) 226 | 227 | # Pad actuals to have same shape 228 | fold_actual = np.pad( 229 | fold_actual, 230 | [ 231 | [0, 0], 232 | [zeros_to_pad, 0], 233 | [0, 0], 234 | ], 235 | ) 236 | 237 | self.actual_.append(fold_actual) 238 | 239 | # Pad expecteds to have same shape 240 | fold_expected = np.pad( 241 | fold_expected, 242 | [ 243 | [0, 0], 244 | [zeros_to_pad, 0], 245 | [0, 0], 246 | ], 247 | ) 248 | 249 | self.expected_.append(fold_expected) 250 | 251 | self.actual_ = np.concatenate(self.actual_, axis=0) 252 | self.expected_ = np.concatenate(self.expected_, axis=2).T 253 | self.t_ = ( 254 | np.repeat( 255 | np.arange(1, self.actual_.shape[1] + 1).reshape(-1, 1)[np.newaxis, ...], 256 | self.cv.n_splits, 257 | axis=0, 258 | ) 259 | / self.actual_.shape[1] 260 | ) 261 | self._output = np.zeros(self.actual_.shape) 262 | self.origin_dim = self.actual_.shape[1] 263 | 264 | if self.verbose: 265 | print() 266 | 267 | return self 268 | 269 | def _softmax(self, x): 270 | return np.exp(x) / np.exp(x).sum(axis=2, keepdims=True) 271 | 272 | def _softmax_gradient(self, x): 273 | identity = np.repeat( 274 | np.repeat(np.eye(x.shape[2])[np.newaxis, ...], x.shape[1], axis=0)[ 275 | np.newaxis, ... 276 | ], 277 | x.shape[0], 278 | axis=0, 279 | ) 280 | lhs_jacobian = identity * self._softmax(x)[..., np.newaxis] 281 | rhs_jacobian = np.einsum("fij,kif->fijk", self._softmax(x), self._softmax(x).T) 282 | return lhs_jacobian - rhs_jacobian 283 | 284 | def dense(self, t): 285 | if self.weight_function is None: 286 | return t * self.weights + self.biases 287 | elif self.weight_function == "linear": 288 | return np.matmul(t, self.weights) + self.biases 289 | elif self.weight_function[:4] == "poly": 290 | return ( 291 | sum( 292 | [t ** (n + 1) * self.weights for n in range(self.weight_polynomial)] 293 | ) 294 | + self.biases 295 | ) 296 | else: 297 | raise Exception( 298 | "Unknown weight function provided. Options are None, linear, or poly(n)." 299 | ) 300 | 301 | def _dense_gradient(self, t): 302 | if self.weight_function is None: 303 | return t 304 | elif self.weight_function == "linear": 305 | return t 306 | elif self.weight_function[:4] == "poly": 307 | return sum([(n + 1) * t ** (n) for n in range(self.weight_polynomial)]) 308 | else: 309 | raise Exception( 310 | "Unknown weight function provided. Options are None, linear, or poly(n)." 311 | ) 312 | 313 | def activation(self, x): 314 | return self._softmax(x) 315 | 316 | def output(self, expected, activation): 317 | return (expected * activation).sum(axis=2, keepdims=True) 318 | 319 | def compute_loss(self, output, actual): 320 | return self.Loss()._loss(output, actual) 321 | 322 | def forward_pass(self, actual, expected, t, text_file=None): 323 | if self.verbose > 2: 324 | print("Starting weights: ", self.weights, " ", self.biases, file=text_file) 325 | self._dense = self.dense(t) 326 | self._activation = self.activation(self._dense) 327 | self._output = self.output(expected, self._activation) 328 | self._compute_loss = self.compute_loss(self._output, actual) 329 | if self.verbose > 2: 330 | print("Loss: ", self._compute_loss, file=text_file) 331 | 332 | return self 333 | 334 | def backward_pass(self, actual, expected, t, epoch, text_file): 335 | dLdy = self.Loss()._loss_gradient(self._output, actual) 336 | dyds = expected 337 | dsdd = self._softmax_gradient(self._dense) 338 | dddw = self._dense_gradient(t) 339 | dddb = np.ones(t.shape) 340 | 341 | dLdd = np.einsum("fkij,fkj->fki", dsdd, dLdy * dyds) 342 | 343 | self._w_grad = (dLdd * dddw).mean(axis=(0, 1)) 344 | self._b_grad = (dLdd * dddb).mean(axis=(0, 1)) 345 | 346 | self.optimizer.pre_update_params(epoch) 347 | self.optimizer.update_params(self, epoch) 348 | 349 | if self.verbose > 2: 350 | print( 351 | "[EPOCH: ", 352 | epoch, 353 | "]: cust_w_grad: ", 354 | self._w_grad, 355 | ", cust_b_grad: ", 356 | self._b_grad, 357 | file=text_file, 358 | ) 359 | 360 | return self 361 | 362 | def _log_epoch(self, epoch): 363 | if not epoch % 10: 364 | print( 365 | f"[Epoch {epoch}/{self.max_iter}] " 366 | + f"loss: {self._loss:.4f} " 367 | + f"lr: {self.optimizer._learning_rate:.8f}" 368 | ) 369 | 370 | def fit(self, X, y=None, sample_weight=None, loss="mse", text_file=None): 371 | 372 | self.compile(X, y, sample_weight) 373 | self.Loss = LOSS_FUNCTIONS[self.loss] 374 | 375 | if self.verbose: 376 | print("[Training]\n") 377 | 378 | num_folds = self.actual_.shape[0] 379 | 380 | weights = [] 381 | biases = [] 382 | eval_losses = [] 383 | 384 | for p in range(num_folds): 385 | 386 | actual_train = np.delete(self.actual_, p, axis=0) 387 | expected_train = np.delete(self.expected_, p, axis=0) 388 | t_train = np.delete(self.t_, p, axis=0) 389 | 390 | actual_test = self.actual_[np.newaxis, p, :, :] 391 | expected_test = self.expected_[np.newaxis, p, :, :] 392 | t_test = self.t_[np.newaxis, p, :, :] 393 | 394 | self.initialize_weights() 395 | self.optimizer.reset(self) 396 | 397 | for epoch in range(self.max_iter + 1): 398 | _actual_train = actual_train 399 | _expected_train = expected_train 400 | _t_train = t_train 401 | 402 | if self.dropout: 403 | drop_mask = np.ones_like( 404 | _actual_train.reshape(-1, _actual_train.shape[-1]) 405 | ) 406 | choices = list(range(drop_mask.shape[0])) 407 | drop_idx = np.random.choice( 408 | choices, int(len(choices) * self.dropout) 409 | ) 410 | drop_mask[drop_idx] = 0 411 | drop_mask = drop_mask.reshape(_actual_train.shape) 412 | 413 | _actual_train = _actual_train * drop_mask 414 | _expected_train = _expected_train * drop_mask 415 | 416 | if self.broad_dropout: 417 | choices = list(range(_actual_train.shape[0])) 418 | drop_idx = np.random.choice( 419 | choices, int(len(choices) * self.broad_dropout) 420 | ) 421 | drop_mask = np.ones_like(_actual_train) 422 | drop_mask[drop_idx, :, :] = 0 423 | 424 | _actual_train = _actual_train * drop_mask 425 | _expected_train = _expected_train * drop_mask 426 | 427 | self.forward_pass(_actual_train, _expected_train, _t_train, text_file) 428 | self.backward_pass( 429 | _actual_train, _expected_train, _t_train, epoch, text_file 430 | ) 431 | 432 | if self.verbose: 433 | self._log_epoch(epoch) 434 | 435 | weights.append(self.weights) 436 | biases.append(self.biases) 437 | 438 | eval_loss = self.compute_loss( 439 | self._predict(expected_test, t_test), actual_test 440 | ) 441 | eval_loss = eval_loss / actual_test.mean() 442 | eval_losses.append(eval_loss) 443 | 444 | self.weights = np.average(np.stack(weights, axis=1), axis=1) 445 | self.biases = np.average(np.stack(biases, axis=1), axis=1) 446 | 447 | self.weights_ = self._activation[-1] 448 | 449 | print() 450 | if self.verbose: 451 | print("\n") 452 | 453 | return self 454 | 455 | def _predict(self, expected, t): 456 | dense = self.dense(t) 457 | activation = self.activation(dense) 458 | output = self.output(expected, activation) 459 | return output 460 | 461 | def predict(self, X, y=None, sample_weight=None): 462 | _, expected, t = self.preprocess(X, y, sample_weight) 463 | return self._predict(expected, t) 464 | 465 | def evaluate(self, X, y=None, sample_weight=None): 466 | actual, expected, t = self.preprocess(X, y, sample_weight) 467 | output = self._predict(expected, t) 468 | return self.compute_loss(output, actual) 469 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. --------------------------------------------------------------------------------