adstk 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adstk-0.0.1/.forgejo/workflows/ci.yaml +22 -0
- adstk-0.0.1/.gitignore +236 -0
- adstk-0.0.1/AGENTS.md +26 -0
- adstk-0.0.1/CHANGELOG.md +13 -0
- adstk-0.0.1/CITATION.cff +10 -0
- adstk-0.0.1/CODE_OF_CONDUCT.md +25 -0
- adstk-0.0.1/CONTRIBUTING.md +60 -0
- adstk-0.0.1/LICENSE +18 -0
- adstk-0.0.1/PKG-INFO +107 -0
- adstk-0.0.1/README.md +71 -0
- adstk-0.0.1/docs/index.md +13 -0
- adstk-0.0.1/examples/README.md +3 -0
- adstk-0.0.1/examples/plot_ice_curves.py +69 -0
- adstk-0.0.1/mkdocs.yml +35 -0
- adstk-0.0.1/pyproject.toml +71 -0
- adstk-0.0.1/src/adstk/__init__.py +10 -0
- adstk-0.0.1/src/adstk/inspect/__init__.py +8 -0
- adstk-0.0.1/src/adstk/inspect/ice.py +164 -0
- adstk-0.0.1/src/adstk/py.typed +0 -0
- adstk-0.0.1/tests/__init__.py +0 -0
- adstk-0.0.1/tests/inspect/test_ice.py +81 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
on:
|
|
2
|
+
push:
|
|
3
|
+
branches: [main]
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
test:
|
|
8
|
+
runs-on: docker
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v4
|
|
11
|
+
- run: pip install ".[dev]"
|
|
12
|
+
- run: ruff check .
|
|
13
|
+
- run: mypy src/
|
|
14
|
+
- run: pytest
|
|
15
|
+
|
|
16
|
+
docs:
|
|
17
|
+
runs-on: docker
|
|
18
|
+
needs: test
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- run: pip install ".[docs]"
|
|
22
|
+
- run: mkdocs build --strict
|
adstk-0.0.1/.gitignore
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# ---> Python
|
|
2
|
+
# Byte-compiled / optimized / DLL files
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[codz]
|
|
5
|
+
*$py.class
|
|
6
|
+
|
|
7
|
+
# C extensions
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# Distribution / packaging
|
|
11
|
+
.Python
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.nox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage.*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
*.cover
|
|
50
|
+
*.py.cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# UV
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi
|
|
127
|
+
|
|
128
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
129
|
+
__pypackages__/
|
|
130
|
+
|
|
131
|
+
# Celery stuff
|
|
132
|
+
celerybeat-schedule
|
|
133
|
+
celerybeat.pid
|
|
134
|
+
|
|
135
|
+
# Redis
|
|
136
|
+
*.rdb
|
|
137
|
+
*.aof
|
|
138
|
+
*.pid
|
|
139
|
+
|
|
140
|
+
# RabbitMQ
|
|
141
|
+
mnesia/
|
|
142
|
+
rabbitmq/
|
|
143
|
+
rabbitmq-data/
|
|
144
|
+
|
|
145
|
+
# ActiveMQ
|
|
146
|
+
activemq-data/
|
|
147
|
+
|
|
148
|
+
# SageMath parsed files
|
|
149
|
+
*.sage.py
|
|
150
|
+
|
|
151
|
+
# Environments
|
|
152
|
+
.env
|
|
153
|
+
.envrc
|
|
154
|
+
.venv
|
|
155
|
+
env/
|
|
156
|
+
venv/
|
|
157
|
+
ENV/
|
|
158
|
+
env.bak/
|
|
159
|
+
venv.bak/
|
|
160
|
+
|
|
161
|
+
# Spyder project settings
|
|
162
|
+
.spyderproject
|
|
163
|
+
.spyproject
|
|
164
|
+
|
|
165
|
+
# Rope project settings
|
|
166
|
+
.ropeproject
|
|
167
|
+
|
|
168
|
+
# mkdocs documentation
|
|
169
|
+
/site
|
|
170
|
+
|
|
171
|
+
# mypy
|
|
172
|
+
.mypy_cache/
|
|
173
|
+
.dmypy.json
|
|
174
|
+
dmypy.json
|
|
175
|
+
|
|
176
|
+
# Pyre type checker
|
|
177
|
+
.pyre/
|
|
178
|
+
|
|
179
|
+
# pytype static type analyzer
|
|
180
|
+
.pytype/
|
|
181
|
+
|
|
182
|
+
# Cython debug symbols
|
|
183
|
+
cython_debug/
|
|
184
|
+
|
|
185
|
+
# PyCharm
|
|
186
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
187
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
188
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
189
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
190
|
+
# .idea/
|
|
191
|
+
|
|
192
|
+
# Abstra
|
|
193
|
+
# Abstra is an AI-powered process automation framework.
|
|
194
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
195
|
+
# Learn more at https://abstra.io/docs
|
|
196
|
+
.abstra/
|
|
197
|
+
|
|
198
|
+
# Visual Studio Code
|
|
199
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
200
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
201
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
202
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
203
|
+
# .vscode/
|
|
204
|
+
|
|
205
|
+
# Ruff stuff:
|
|
206
|
+
.ruff_cache/
|
|
207
|
+
|
|
208
|
+
# PyPI configuration file
|
|
209
|
+
.pypirc
|
|
210
|
+
|
|
211
|
+
# Marimo
|
|
212
|
+
marimo/_static/
|
|
213
|
+
marimo/_lsp/
|
|
214
|
+
__marimo__/
|
|
215
|
+
|
|
216
|
+
# Streamlit
|
|
217
|
+
.streamlit/secrets.toml
|
|
218
|
+
|
|
219
|
+
# ---> JupyterNotebooks
|
|
220
|
+
# gitignore template for Jupyter Notebooks
|
|
221
|
+
# website: http://jupyter.org/
|
|
222
|
+
|
|
223
|
+
.ipynb_checkpoints
|
|
224
|
+
*/.ipynb_checkpoints/*
|
|
225
|
+
|
|
226
|
+
# IPython
|
|
227
|
+
profile_default/
|
|
228
|
+
ipython_config.py
|
|
229
|
+
|
|
230
|
+
# Jupyter lab virtual documents
|
|
231
|
+
# https://jupyterlab-lsp.readthedocs.io/en/2.x/Configuring.html#virtual_documents_dir
|
|
232
|
+
.virtual_documents/
|
|
233
|
+
|
|
234
|
+
# Remove previous ipynb_checkpoints
|
|
235
|
+
# git rm -r .ipynb_checkpoints/
|
|
236
|
+
|
adstk-0.0.1/AGENTS.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This document outlines the AI policy of the ADSTK project at https://codeberg.org/ftranschel/adstk
|
|
4
|
+
|
|
5
|
+
## General guidelines
|
|
6
|
+
|
|
7
|
+
- No automated LLM PRs and bug reports. All submissions to the project have to go through a human. We expect that the human reporter / puller fully understands every single bit of their submission. If we find that not to be the case, the issue/PR in question will be diuscarded. (Yes, even if a hypothetical bug report is valid per se.)
|
|
8
|
+
- If you submit code that is partly LLM-generated, we expect full disclosure. If we find violations of this, we will revoke access and, quite possibly, remove the submission(s).
|
|
9
|
+
|
|
10
|
+
## AGENTS Instruction
|
|
11
|
+
|
|
12
|
+
This file contains additional guidance for AI agents and other AI editors.
|
|
13
|
+
|
|
14
|
+
**REQUIRED: AI/Agent Disclosure**
|
|
15
|
+
|
|
16
|
+
Every summary, pull request description, or work description MUST include this disclosure:
|
|
17
|
+
|
|
18
|
+
If human review has not occurred (use this initially):
|
|
19
|
+
|
|
20
|
+
This pull request includes code written with the assistance of AI. The code has not been reviewed by a human.
|
|
21
|
+
|
|
22
|
+
This is a mandatory requirement, not optional. Include it at the end of every summary you generate.
|
|
23
|
+
|
|
24
|
+
## Working on an issue
|
|
25
|
+
|
|
26
|
+
Before working on any issue, run gh issue view <number> to check current labels. Do not open a PR against an issue labeled "Needs Triage" or another "Needs ..." label. Such PRs get closed without review until a maintainer clears the label.
|
adstk-0.0.1/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Nothing worth a mention at all.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Created empty project framework for adstk.
|
|
10
|
+
|
|
11
|
+
## [0.0.1] - Initial Commit
|
|
12
|
+
|
|
13
|
+
- Initial commit preparing the framework for pull requests of actual models. No PyPI hook yet.
|
adstk-0.0.1/CITATION.cff
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "Wenn du adstk in wissenschaftlicher Arbeit nutzt, zitiere es bitte wie folgt:"
|
|
3
|
+
title: "adstk: Actuarial Data Science Toolkit"
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
date-released: 2026-09-17
|
|
6
|
+
authors:
|
|
7
|
+
- family-names: "Transchel"
|
|
8
|
+
given-names: "Fabian"
|
|
9
|
+
url: "https://codeberg.org/ftranschel/adstk"
|
|
10
|
+
license: MIT
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# adstk code of conduct
|
|
2
|
+
|
|
3
|
+
The aim of this CoC: Maximal inclusivity for humans, clear guardrails for agents and LLM submissions. Zero tolerance for misconduct of any kind.
|
|
4
|
+
|
|
5
|
+
## Expected conduct
|
|
6
|
+
|
|
7
|
+
- Be respectful and constructive in PRs, issues and all other interactions.
|
|
8
|
+
- Be constructive w.r.t. the code. No ad hominems.
|
|
9
|
+
|
|
10
|
+
## Inacceptable conduct
|
|
11
|
+
|
|
12
|
+
- No insults and offenses.
|
|
13
|
+
- No discrimination.
|
|
14
|
+
|
|
15
|
+
## AI policy
|
|
16
|
+
|
|
17
|
+
- No automated LLM PRs and bug reports. All submissions to the project have to go through a human. We expect that the human reporter / puller fully understands every single bit of their submission. If we find that not to be the case, the issue/PR in question will be diuscarded. (Yes, even if a hypothetical bug report is valid per se.)
|
|
18
|
+
- If you submit code that is partly LLM-generated, we expect full disclosure. If we find violations of this, we will revoke access and, quite possibly, remove the submission(s).
|
|
19
|
+
|
|
20
|
+
## Violations to this CoC
|
|
21
|
+
|
|
22
|
+
Infractions are to be pointed at ftranschel@hs-harz.de.
|
|
23
|
+
Dealings are confidential unless otherwise required.
|
|
24
|
+
|
|
25
|
+
The codex is based on [Contributor Covenant](https://www.contributor-covenant.org/). All changes are our own interpretation of the aims and guidelines formulated therein.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Contributing to adstk
|
|
2
|
+
|
|
3
|
+
We appreciate submissions to adstk as long as they allow progress for both the actuarial profession as well as the package scope and health.
|
|
4
|
+
|
|
5
|
+
Here's how to help:
|
|
6
|
+
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://codeberg.org/ftranschel/adstk.git
|
|
11
|
+
cd adstk
|
|
12
|
+
python -m venv .venv
|
|
13
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
14
|
+
pip install -e ".[dev,docs]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Tests & Lint lokal ausführen
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pytest
|
|
21
|
+
ruff check .
|
|
22
|
+
mypy src/
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Contributing a new model
|
|
26
|
+
|
|
27
|
+
1. Open an issue using the "Model request" template (or pick up an
|
|
28
|
+
existing one), including a professional reference (paper, textbook, standard).
|
|
29
|
+
2. Create a new submodule under `src/adstk/<area>/` (e.g.
|
|
30
|
+
`src/adstk/explain/`, `src/adstk/telematics/` - depending on the topic area).
|
|
31
|
+
3. Use NumPy-style docstrings (including the formula, parameters, returns,
|
|
32
|
+
examples) - this automatically generates the API documentation.
|
|
33
|
+
4. Add tests under `tests/`, in particular numerical reference values
|
|
34
|
+
checked against an independent source (textbook, R package, etc.).
|
|
35
|
+
5. Open a pull request. Note: any LLM involvement in your submission must
|
|
36
|
+
be fully disclosed - see [AGENTS.md](AGENTS.md).
|
|
37
|
+
|
|
38
|
+
## Docstring style (NumPy format)
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
def example(x: float, a: float) -> float:
|
|
42
|
+
"""Short description.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
x : float
|
|
47
|
+
Description.
|
|
48
|
+
a : float
|
|
49
|
+
Description.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
float
|
|
54
|
+
Description.
|
|
55
|
+
"""
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Verhaltenskodex
|
|
59
|
+
|
|
60
|
+
Please follow our [Code of Conduct](CODE_OF_CONDUCT.md).
|
adstk-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ftranschel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
adstk-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: adstk
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: ADSTK aims to bundle together relevant actuarial models, tools and code simplifications to enrich the Actuarial / Insurance Data Science experience in the Python ecosystem.
|
|
5
|
+
Project-URL: Homepage, https://codeberg.org/ftranschel/adstk
|
|
6
|
+
Project-URL: Repository, https://codeberg.org/ftranschel/adstk
|
|
7
|
+
Project-URL: Issues, https://codeberg.org/ftranschel/adstk/issues
|
|
8
|
+
Project-URL: Documentation, https://ftranschel.codeberg.page/adstk/
|
|
9
|
+
Author-email: Fabian Transchel <ftranschel@hs-harz.de>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: actuarial,aktuariat,data science,inspection,insurance,pricing,telematics
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: numpy>=1.24
|
|
25
|
+
Requires-Dist: pandas>=1.5
|
|
26
|
+
Requires-Dist: scipy>=1.10
|
|
27
|
+
Provides-Extra: docs
|
|
28
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
29
|
+
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: matplotlib; extra == 'test'
|
|
32
|
+
Requires-Dist: pytest; extra == 'test'
|
|
33
|
+
Requires-Dist: pytest-cov; extra == 'test'
|
|
34
|
+
Requires-Dist: scikit-learn; extra == 'test'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# adstk
|
|
38
|
+
|
|
39
|
+
ADSTK aims to bundle together relevant actuarial models, tools and code simplifications to enrich the Actuarial / Insurance Data Science experience in the Python ecosystem.
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
ADSTK currently ships with a limited number of methods and use cases:
|
|
45
|
+
|
|
46
|
+
* Partial dependence display with support for individual conditional expectation curves (ICE)
|
|
47
|
+
|
|
48
|
+
### Dependencies
|
|
49
|
+
|
|
50
|
+
adstk requires:
|
|
51
|
+
|
|
52
|
+
- Python (>= 3.10)
|
|
53
|
+
- NumPy (>= 1.24)
|
|
54
|
+
- SciPy (>= 1.10)
|
|
55
|
+
|
|
56
|
+
Optional requirements for plotting etc.
|
|
57
|
+
|
|
58
|
+
- matplotlib ()
|
|
59
|
+
- plotly ()
|
|
60
|
+
|
|
61
|
+
### User installation
|
|
62
|
+
|
|
63
|
+
The easiest way to install adstk will using `pip` once we publish on PyPi:
|
|
64
|
+
|
|
65
|
+
pip install -U adstk
|
|
66
|
+
|
|
67
|
+
## Changelog
|
|
68
|
+
|
|
69
|
+
See the [changelog](CHANGELOG.md) for a history of notable changes to adstk.
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
We welcome human contributors of all experience levels. The adstk community
|
|
74
|
+
goals are to be helpful, welcoming, and effective. The
|
|
75
|
+
[Contributing guide](CONTRIBUTING.md) has detailed information about
|
|
76
|
+
contributing code, documentation, tests, and more. Please also note our
|
|
77
|
+
[AI contribution policy](AGENTS.md) before submitting anything.
|
|
78
|
+
|
|
79
|
+
### Important links
|
|
80
|
+
|
|
81
|
+
- Official source code repo: https://codeberg.org/ftranschel/adstk
|
|
82
|
+
- Download releases: https://pypi.org/project/adstk/
|
|
83
|
+
- Issue tracker: https://codeberg.org/ftranschel/adstk/issues
|
|
84
|
+
|
|
85
|
+
### Source code
|
|
86
|
+
|
|
87
|
+
You can check the latest sources with the command:
|
|
88
|
+
|
|
89
|
+
git clone https://codeberg.org/ftranschel/adstk.git
|
|
90
|
+
|
|
91
|
+
### Contributing
|
|
92
|
+
|
|
93
|
+
To learn more about making a contribution to adstk, please see our
|
|
94
|
+
[Contributing guide](CONTRIBUTING.md).
|
|
95
|
+
|
|
96
|
+
### Testing
|
|
97
|
+
|
|
98
|
+
After installation, you can launch the test suite from the source
|
|
99
|
+
directory (you will need `pytest` installed):
|
|
100
|
+
|
|
101
|
+
pytest
|
|
102
|
+
|
|
103
|
+
### Submitting a Pull Request
|
|
104
|
+
|
|
105
|
+
Before opening a pull request, please read the
|
|
106
|
+
[Contributing guide](CONTRIBUTING.md) and our [AI policy](AGENTS.md) to
|
|
107
|
+
make sure your submission complies with our guidelines.
|
adstk-0.0.1/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# adstk
|
|
2
|
+
|
|
3
|
+
ADSTK aims to bundle together relevant actuarial models, tools and code simplifications to enrich the Actuarial / Insurance Data Science experience in the Python ecosystem.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
ADSTK currently ships with a limited number of methods and use cases:
|
|
9
|
+
|
|
10
|
+
* Partial dependence display with support for individual conditional expectation curves (ICE)
|
|
11
|
+
|
|
12
|
+
### Dependencies
|
|
13
|
+
|
|
14
|
+
adstk requires:
|
|
15
|
+
|
|
16
|
+
- Python (>= 3.10)
|
|
17
|
+
- NumPy (>= 1.24)
|
|
18
|
+
- SciPy (>= 1.10)
|
|
19
|
+
|
|
20
|
+
Optional requirements for plotting etc.
|
|
21
|
+
|
|
22
|
+
- matplotlib ()
|
|
23
|
+
- plotly ()
|
|
24
|
+
|
|
25
|
+
### User installation
|
|
26
|
+
|
|
27
|
+
The easiest way to install adstk will using `pip` once we publish on PyPi:
|
|
28
|
+
|
|
29
|
+
pip install -U adstk
|
|
30
|
+
|
|
31
|
+
## Changelog
|
|
32
|
+
|
|
33
|
+
See the [changelog](CHANGELOG.md) for a history of notable changes to adstk.
|
|
34
|
+
|
|
35
|
+
## Development
|
|
36
|
+
|
|
37
|
+
We welcome human contributors of all experience levels. The adstk community
|
|
38
|
+
goals are to be helpful, welcoming, and effective. The
|
|
39
|
+
[Contributing guide](CONTRIBUTING.md) has detailed information about
|
|
40
|
+
contributing code, documentation, tests, and more. Please also note our
|
|
41
|
+
[AI contribution policy](AGENTS.md) before submitting anything.
|
|
42
|
+
|
|
43
|
+
### Important links
|
|
44
|
+
|
|
45
|
+
- Official source code repo: https://codeberg.org/ftranschel/adstk
|
|
46
|
+
- Download releases: https://pypi.org/project/adstk/
|
|
47
|
+
- Issue tracker: https://codeberg.org/ftranschel/adstk/issues
|
|
48
|
+
|
|
49
|
+
### Source code
|
|
50
|
+
|
|
51
|
+
You can check the latest sources with the command:
|
|
52
|
+
|
|
53
|
+
git clone https://codeberg.org/ftranschel/adstk.git
|
|
54
|
+
|
|
55
|
+
### Contributing
|
|
56
|
+
|
|
57
|
+
To learn more about making a contribution to adstk, please see our
|
|
58
|
+
[Contributing guide](CONTRIBUTING.md).
|
|
59
|
+
|
|
60
|
+
### Testing
|
|
61
|
+
|
|
62
|
+
After installation, you can launch the test suite from the source
|
|
63
|
+
directory (you will need `pytest` installed):
|
|
64
|
+
|
|
65
|
+
pytest
|
|
66
|
+
|
|
67
|
+
### Submitting a Pull Request
|
|
68
|
+
|
|
69
|
+
Before opening a pull request, please read the
|
|
70
|
+
[Contributing guide](CONTRIBUTING.md) and our [AI policy](AGENTS.md) to
|
|
71
|
+
make sure your submission complies with our guidelines.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# adstk
|
|
2
|
+
|
|
3
|
+
Aktuarielle Modelle für Python - Bausteine, die im Python-Ökosystem
|
|
4
|
+
bislang fehlen oder nur unvollständig implementiert sind.
|
|
5
|
+
|
|
6
|
+
## Erste Schritte
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install adstk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Die API-Referenz wird automatisch aus den Docstrings im Quellcode
|
|
13
|
+
generiert (siehe `docs/api/`), sobald erste Module implementiert sind.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ICE curves for model inspection
|
|
3
|
+
================================
|
|
4
|
+
|
|
5
|
+
This example shows how to compute and plot Individual Conditional
|
|
6
|
+
Expectation (ICE) curves with :func:`adstk.inspect.create_ice_curves`
|
|
7
|
+
and :func:`adstk.inspect.plot_ice_curves`.
|
|
8
|
+
|
|
9
|
+
ICE curves show how a fitted model's prediction for a *single*
|
|
10
|
+
instance changes as one feature is varied while every other feature is
|
|
11
|
+
held fixed. Averaging ICE curves across instances recovers the
|
|
12
|
+
Partial Dependence Plot (PDP).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# %%
|
|
16
|
+
# Fit a model on synthetic data
|
|
17
|
+
# ------------------------------
|
|
18
|
+
# We use a small toy marketing-mix-style dataset: spend on two
|
|
19
|
+
# channels and a price, predicting some outcome.
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
import pandas as pd
|
|
23
|
+
from sklearn.ensemble import RandomForestRegressor
|
|
24
|
+
|
|
25
|
+
from adstk.inspect import create_ice_curves, plot_ice_curves
|
|
26
|
+
|
|
27
|
+
rng = np.random.default_rng(0)
|
|
28
|
+
n_samples = 200
|
|
29
|
+
X = pd.DataFrame(
|
|
30
|
+
{
|
|
31
|
+
"tv_spend": rng.uniform(0, 100, n_samples),
|
|
32
|
+
"social_spend": rng.uniform(0, 50, n_samples),
|
|
33
|
+
"price": rng.uniform(10, 30, n_samples),
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
y = (
|
|
37
|
+
0.8 * X["tv_spend"]
|
|
38
|
+
+ 1.2 * X["social_spend"]
|
|
39
|
+
- 2.0 * X["price"]
|
|
40
|
+
+ rng.normal(0, 5, n_samples)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
model = RandomForestRegressor(n_estimators=100, random_state=0).fit(X, y)
|
|
44
|
+
|
|
45
|
+
# %%
|
|
46
|
+
# Compute raw ICE curve data for a single feature
|
|
47
|
+
# -------------------------------------------------
|
|
48
|
+
# ``create_ice_curves`` returns the grid of swept feature values and a
|
|
49
|
+
# ``(n_instances, n_points)`` array of predictions -- one row per
|
|
50
|
+
# instance, one column per grid point.
|
|
51
|
+
|
|
52
|
+
sample = X.sample(30, random_state=0)
|
|
53
|
+
feature_values, ice_curves = create_ice_curves(model, sample, "tv_spend")
|
|
54
|
+
print(f"feature_values shape: {feature_values.shape}")
|
|
55
|
+
print(f"ice_curves shape: {ice_curves.shape}")
|
|
56
|
+
|
|
57
|
+
# %%
|
|
58
|
+
# Plot ICE curves and the PDP for several features
|
|
59
|
+
# ---------------------------------------------------
|
|
60
|
+
# ``plot_ice_curves`` computes ICE curves for each feature in
|
|
61
|
+
# ``feature_list`` and plots a sample of the individual curves in blue
|
|
62
|
+
# alongside the averaged PDP in red.
|
|
63
|
+
|
|
64
|
+
fig, axes = plot_ice_curves(
|
|
65
|
+
model,
|
|
66
|
+
sample,
|
|
67
|
+
feature_list=["tv_spend", "social_spend", "price"],
|
|
68
|
+
random_state=0,
|
|
69
|
+
)
|
adstk-0.0.1/mkdocs.yml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
site_name: adstk
|
|
2
|
+
site_description: Actuarial Data Science Toolkit
|
|
3
|
+
repo_url: https://codeberg.org/ftranschel/adstk
|
|
4
|
+
docs_dir: docs
|
|
5
|
+
|
|
6
|
+
theme:
|
|
7
|
+
name: material
|
|
8
|
+
features:
|
|
9
|
+
- navigation.sections
|
|
10
|
+
- content.code.copy
|
|
11
|
+
|
|
12
|
+
plugins:
|
|
13
|
+
- search
|
|
14
|
+
- mkdocstrings:
|
|
15
|
+
handlers:
|
|
16
|
+
python:
|
|
17
|
+
options:
|
|
18
|
+
docstring_style: numpy
|
|
19
|
+
show_source: true
|
|
20
|
+
show_root_heading: true
|
|
21
|
+
|
|
22
|
+
markdown_extensions:
|
|
23
|
+
- pymdownx.arithmatex:
|
|
24
|
+
generic: true
|
|
25
|
+
- admonition
|
|
26
|
+
- pymdownx.details
|
|
27
|
+
- pymdownx.superfences
|
|
28
|
+
|
|
29
|
+
extra_javascript:
|
|
30
|
+
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.min.js
|
|
31
|
+
|
|
32
|
+
nav:
|
|
33
|
+
- Start: index.md
|
|
34
|
+
# API-Referenz: Seiten unter docs/api/ ergänzen, sobald erste Module existieren.
|
|
35
|
+
# Beispiel: "::: paket.modul.funktion" in eine .md-Datei, siehe mkdocstrings-Doku.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "adstk"
|
|
7
|
+
version = "0.0.1"
|
|
8
|
+
description = "ADSTK aims to bundle together relevant actuarial models, tools and code simplifications to enrich the Actuarial / Insurance Data Science experience in the Python ecosystem."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Fabian Transchel", email = "ftranschel@hs-harz.de" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["actuarial", "aktuariat", "pricing", "insurance","inspection","telematics","data science"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Office/Business :: Financial",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
"numpy>=1.24",
|
|
31
|
+
"scipy>=1.10",
|
|
32
|
+
"pandas>=1.5", # add this: adstk.inspect needs DataFrame input
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
test = [
|
|
37
|
+
"pytest",
|
|
38
|
+
"pytest-cov",
|
|
39
|
+
"matplotlib",
|
|
40
|
+
"scikit-learn",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
docs = [
|
|
44
|
+
"mkdocs-material>=9.5",
|
|
45
|
+
"mkdocstrings[python]>=0.25",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
Homepage = "https://codeberg.org/ftranschel/adstk"
|
|
50
|
+
Repository = "https://codeberg.org/ftranschel/adstk"
|
|
51
|
+
Issues = "https://codeberg.org/ftranschel/adstk/issues"
|
|
52
|
+
Documentation = "https://ftranschel.codeberg.page/adstk/"
|
|
53
|
+
|
|
54
|
+
[tool.hatch.build.targets.wheel]
|
|
55
|
+
packages = ["src/adstk"]
|
|
56
|
+
|
|
57
|
+
[tool.ruff]
|
|
58
|
+
line-length = 100
|
|
59
|
+
target-version = "py310"
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.10"
|
|
66
|
+
strict = true
|
|
67
|
+
packages = ["adstk"]
|
|
68
|
+
|
|
69
|
+
[tool.pytest.ini_options]
|
|
70
|
+
testpaths = ["tests"]
|
|
71
|
+
addopts = "--cov=adstk --cov-report=term-missing"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""adstk - Actuarial Data Science Toolkit (for Python)
|
|
2
|
+
|
|
3
|
+
ADSTK aims to bundle together relevant actuarial models, tools and code simplifications to enrich the insurance Data Science experience in the Python ecosystem.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Individual Conditional Expectation (ICE) curves.
|
|
2
|
+
|
|
3
|
+
Individual Conditional Expectation (ICE) curves show how a fitted model's
|
|
4
|
+
prediction for a single instance changes as one feature is varied while
|
|
5
|
+
all other features are held fixed. Averaging ICE curves across instances
|
|
6
|
+
recovers the Partial Dependence Plot (PDP).
|
|
7
|
+
|
|
8
|
+
Part of ``adstk.inspect``. Public API:
|
|
9
|
+
|
|
10
|
+
- :func:`create_ice_curves` computes the raw ICE curve data.
|
|
11
|
+
- :func:`plot_ice_curves` computes ICE curves for one or more features
|
|
12
|
+
and renders them, overlaying the PDP.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Optional, Sequence, Tuple
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
import pandas as pd
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_ice_curves(
|
|
24
|
+
model,
|
|
25
|
+
X: pd.DataFrame,
|
|
26
|
+
feature_name: str,
|
|
27
|
+
n_points: int = 50,
|
|
28
|
+
feature_range: Optional[Tuple[float, float]] = None,
|
|
29
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
30
|
+
"""Compute Individual Conditional Expectation (ICE) curves.
|
|
31
|
+
|
|
32
|
+
For every row in ``X``, ``feature_name`` is swept across ``n_points``
|
|
33
|
+
values spanning ``feature_range`` (or the observed min/max) while all
|
|
34
|
+
other feature values are held at their originally observed values,
|
|
35
|
+
and the model's prediction is recorded at each point.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
model : object
|
|
40
|
+
A fitted estimator exposing ``predict(X: np.ndarray) -> np.ndarray``.
|
|
41
|
+
X : pandas.DataFrame
|
|
42
|
+
Instances to compute curves for, with columns in the same order
|
|
43
|
+
the model expects.
|
|
44
|
+
feature_name : str
|
|
45
|
+
Column of ``X`` to vary.
|
|
46
|
+
n_points : int, default=50
|
|
47
|
+
Number of grid points to evaluate the feature at.
|
|
48
|
+
feature_range : tuple(float, float), optional
|
|
49
|
+
``(min, max)`` to sweep over. Defaults to the observed range of
|
|
50
|
+
``feature_name`` in ``X``.
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
feature_values : numpy.ndarray, shape (n_points,)
|
|
55
|
+
The grid ``feature_name`` was evaluated at.
|
|
56
|
+
ice_curves : numpy.ndarray, shape (len(X), n_points)
|
|
57
|
+
``ice_curves[i, j]`` is the prediction for row ``i`` of ``X``
|
|
58
|
+
with ``feature_name`` fixed at ``feature_values[j]``.
|
|
59
|
+
|
|
60
|
+
Raises
|
|
61
|
+
------
|
|
62
|
+
KeyError
|
|
63
|
+
If ``feature_name`` is not a column of ``X``.
|
|
64
|
+
ValueError
|
|
65
|
+
If ``X`` has no rows, or ``feature_range`` is decreasing.
|
|
66
|
+
"""
|
|
67
|
+
if feature_name not in X.columns:
|
|
68
|
+
raise KeyError(
|
|
69
|
+
f"'{feature_name}' is not a column of X. "
|
|
70
|
+
f"Available columns: {list(X.columns)}"
|
|
71
|
+
)
|
|
72
|
+
if len(X) == 0:
|
|
73
|
+
raise ValueError("X must contain at least one row.")
|
|
74
|
+
|
|
75
|
+
if feature_range is None:
|
|
76
|
+
feature_min = X[feature_name].min()
|
|
77
|
+
feature_max = X[feature_name].max()
|
|
78
|
+
else:
|
|
79
|
+
feature_min, feature_max = feature_range
|
|
80
|
+
if feature_min > feature_max:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"feature_range must not be decreasing, got ({feature_min}, {feature_max})."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
feature_values = np.linspace(feature_min, feature_max, n_points)
|
|
86
|
+
|
|
87
|
+
n_samples = len(X)
|
|
88
|
+
feature_idx = X.columns.get_loc(feature_name)
|
|
89
|
+
|
|
90
|
+
# Build a single batch of (n_samples * n_points) modified rows so
|
|
91
|
+
# predict() is called once instead of n_samples * n_points times.
|
|
92
|
+
# This is the main cost driver for ICE curves at any real n_points.
|
|
93
|
+
batch = np.repeat(X.to_numpy(), n_points, axis=0)
|
|
94
|
+
batch[:, feature_idx] = np.tile(feature_values, n_samples)
|
|
95
|
+
|
|
96
|
+
predictions = np.asarray(model.predict(batch)).reshape(n_samples, n_points)
|
|
97
|
+
|
|
98
|
+
return feature_values, predictions
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def plot_ice_curves(
|
|
102
|
+
model,
|
|
103
|
+
X: pd.DataFrame,
|
|
104
|
+
feature_list: Sequence[str],
|
|
105
|
+
n_points: int = 50,
|
|
106
|
+
n_ice_lines: int = 25,
|
|
107
|
+
random_state: Optional[int] = None,
|
|
108
|
+
):
|
|
109
|
+
"""Plot ICE curves (with overlaid PDP) for one or more features.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
model : object
|
|
114
|
+
A fitted estimator exposing ``predict``.
|
|
115
|
+
X : pandas.DataFrame
|
|
116
|
+
Instances to compute curves for. Pass a sample rather than the
|
|
117
|
+
full dataset -- cost scales with ``len(X) * n_points``.
|
|
118
|
+
feature_list : sequence of str
|
|
119
|
+
Feature columns to plot, one subplot each.
|
|
120
|
+
n_points : int, default=50
|
|
121
|
+
Grid resolution per feature.
|
|
122
|
+
n_ice_lines : int, default=25
|
|
123
|
+
Number of individual ICE curves to draw per subplot (drawing
|
|
124
|
+
all of ``len(X)`` gets unreadable fast).
|
|
125
|
+
random_state : int, optional
|
|
126
|
+
Seed controlling which instances are sampled for display.
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
fig : matplotlib.figure.Figure
|
|
131
|
+
axes : numpy.ndarray of matplotlib.axes.Axes
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
import matplotlib.pyplot as plt
|
|
135
|
+
except ImportError as exc: # pragma: no cover
|
|
136
|
+
raise ImportError(
|
|
137
|
+
"plot_ice_curves requires matplotlib. Install it with "
|
|
138
|
+
"`pip install matplotlib`."
|
|
139
|
+
) from exc
|
|
140
|
+
|
|
141
|
+
rng = np.random.default_rng(random_state)
|
|
142
|
+
|
|
143
|
+
fig, axes = plt.subplots(1, len(feature_list), figsize=(5 * len(feature_list), 4))
|
|
144
|
+
axes = np.atleast_1d(axes)
|
|
145
|
+
|
|
146
|
+
for ax, feature in zip(axes, feature_list):
|
|
147
|
+
feature_vals, ice_data = create_ice_curves(model, X, feature, n_points)
|
|
148
|
+
|
|
149
|
+
n_lines = min(n_ice_lines, len(ice_data))
|
|
150
|
+
sample_indices = rng.choice(len(ice_data), n_lines, replace=False)
|
|
151
|
+
for idx in sample_indices:
|
|
152
|
+
ax.plot(feature_vals, ice_data[idx], alpha=0.4, color="tab:blue", linewidth=1)
|
|
153
|
+
|
|
154
|
+
pdp = np.mean(ice_data, axis=0)
|
|
155
|
+
ax.plot(feature_vals, pdp, color="tab:red", linewidth=2, label="PDP")
|
|
156
|
+
|
|
157
|
+
ax.set_xlabel(feature)
|
|
158
|
+
ax.set_ylabel("Prediction")
|
|
159
|
+
ax.set_title(f"ICE: {feature}")
|
|
160
|
+
ax.grid(True, alpha=0.3)
|
|
161
|
+
ax.legend()
|
|
162
|
+
|
|
163
|
+
fig.tight_layout()
|
|
164
|
+
return fig, axes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Tests for adstk.inspect.ice."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from adstk.inspect.ice import create_ice_curves, plot_ice_curves
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _LinearStub:
|
|
11
|
+
"""Deterministic stand-in for a fitted model: predict = row sum."""
|
|
12
|
+
|
|
13
|
+
def predict(self, X):
|
|
14
|
+
return X.sum(axis=1)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture
|
|
18
|
+
def sample_data():
|
|
19
|
+
return pd.DataFrame(
|
|
20
|
+
{
|
|
21
|
+
"a": [0.0, 1.0, 2.0],
|
|
22
|
+
"b": [10.0, 10.0, 10.0],
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_create_ice_curves_shape(sample_data):
|
|
28
|
+
feature_values, ice_curves = create_ice_curves(_LinearStub(), sample_data, "a", n_points=5)
|
|
29
|
+
assert feature_values.shape == (5,)
|
|
30
|
+
assert ice_curves.shape == (len(sample_data), 5)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_create_ice_curves_default_range_matches_data(sample_data):
|
|
34
|
+
feature_values, _ = create_ice_curves(_LinearStub(), sample_data, "a", n_points=5)
|
|
35
|
+
assert feature_values[0] == pytest.approx(sample_data["a"].min())
|
|
36
|
+
assert feature_values[-1] == pytest.approx(sample_data["a"].max())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_create_ice_curves_explicit_range(sample_data):
|
|
40
|
+
feature_values, _ = create_ice_curves(
|
|
41
|
+
_LinearStub(), sample_data, "a", n_points=5, feature_range=(-5, 5)
|
|
42
|
+
)
|
|
43
|
+
assert feature_values[0] == pytest.approx(-5)
|
|
44
|
+
assert feature_values[-1] == pytest.approx(5)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_create_ice_curves_values_correct(sample_data):
|
|
48
|
+
# predict = a + b, and b is fixed at 10 for every row here, so each
|
|
49
|
+
# ICE curve should equal 10 + the swept 'a' grid exactly, regardless
|
|
50
|
+
# of that row's original 'a' value.
|
|
51
|
+
feature_values, ice_curves = create_ice_curves(_LinearStub(), sample_data, "a", n_points=5)
|
|
52
|
+
expected = 10.0 + feature_values
|
|
53
|
+
for row in ice_curves:
|
|
54
|
+
np.testing.assert_allclose(row, expected)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_create_ice_curves_missing_feature_raises(sample_data):
|
|
58
|
+
with pytest.raises(KeyError):
|
|
59
|
+
create_ice_curves(_LinearStub(), sample_data, "does_not_exist")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_create_ice_curves_empty_X_raises(sample_data):
|
|
63
|
+
with pytest.raises(ValueError):
|
|
64
|
+
create_ice_curves(_LinearStub(), sample_data.iloc[0:0], "a")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_create_ice_curves_invalid_range_raises(sample_data):
|
|
68
|
+
with pytest.raises(ValueError):
|
|
69
|
+
create_ice_curves(_LinearStub(), sample_data, "a", feature_range=(5, -5))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_plot_ice_curves_returns_figure_and_axes(sample_data):
|
|
73
|
+
matplotlib = pytest.importorskip("matplotlib")
|
|
74
|
+
matplotlib.use("Agg") # headless backend for CI
|
|
75
|
+
|
|
76
|
+
fig, axes = plot_ice_curves(
|
|
77
|
+
_LinearStub(), sample_data, feature_list=["a", "b"], n_points=5, random_state=0
|
|
78
|
+
)
|
|
79
|
+
assert len(axes) == 2
|
|
80
|
+
for ax in axes:
|
|
81
|
+
assert len(ax.lines) >= 1 # at least the PDP line was drawn
|