limno 0.1.0__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.
- limno-0.1.0/.github/workflows/ci.yml +56 -0
- limno-0.1.0/.github/workflows/publish.yml +20 -0
- limno-0.1.0/.gitignore +14 -0
- limno-0.1.0/.readthedocs.yaml +18 -0
- limno-0.1.0/AGENTS.md +46 -0
- limno-0.1.0/CHANGELOG.md +35 -0
- limno-0.1.0/CITATION.cff +23 -0
- limno-0.1.0/LICENSE +28 -0
- limno-0.1.0/PKG-INFO +121 -0
- limno-0.1.0/README.md +92 -0
- limno-0.1.0/docs/api/base.rst +4 -0
- limno-0.1.0/docs/api/importance.rst +5 -0
- limno-0.1.0/docs/api/imputer.rst +4 -0
- limno-0.1.0/docs/api/index.md +12 -0
- limno-0.1.0/docs/api/multioutput.rst +4 -0
- limno-0.1.0/docs/api/storage.rst +4 -0
- limno-0.1.0/docs/api/tracker.rst +4 -0
- limno-0.1.0/docs/conf.py +36 -0
- limno-0.1.0/docs/index.md +20 -0
- limno-0.1.0/docs/installation.md +14 -0
- limno-0.1.0/docs/quickstart.md +168 -0
- limno-0.1.0/pyproject.toml +57 -0
- limno-0.1.0/src/limno/__init__.py +14 -0
- limno-0.1.0/src/limno/base.py +305 -0
- limno-0.1.0/src/limno/importance/__init__.py +9 -0
- limno-0.1.0/src/limno/importance/_base.py +98 -0
- limno-0.1.0/src/limno/importance/pfi.py +110 -0
- limno-0.1.0/src/limno/importance/sage.py +194 -0
- limno-0.1.0/src/limno/imputer.py +62 -0
- limno-0.1.0/src/limno/multioutput.py +150 -0
- limno-0.1.0/src/limno/storage.py +88 -0
- limno-0.1.0/src/limno/tracker.py +77 -0
- limno-0.1.0/tests/test_base.py +80 -0
- limno-0.1.0/tests/test_import.py +73 -0
- limno-0.1.0/tests/test_importance.py +678 -0
- limno-0.1.0/tests/test_imputer.py +51 -0
- limno-0.1.0/tests/test_multioutput.py +173 -0
- limno-0.1.0/tests/test_river.py +477 -0
- limno-0.1.0/tests/test_storage.py +85 -0
- limno-0.1.0/tests/test_tracker.py +57 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
cache: pip
|
|
21
|
+
- run: pip install -e ".[dev]"
|
|
22
|
+
- run: ruff check .
|
|
23
|
+
- run: ruff format --check .
|
|
24
|
+
- run: mypy src
|
|
25
|
+
|
|
26
|
+
test:
|
|
27
|
+
runs-on: ${{ matrix.os }}
|
|
28
|
+
strategy:
|
|
29
|
+
fail-fast: false
|
|
30
|
+
matrix:
|
|
31
|
+
os: [ubuntu-latest]
|
|
32
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
33
|
+
include:
|
|
34
|
+
- os: windows-latest
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
- os: macos-latest
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
cache: pip
|
|
44
|
+
- run: pip install -e ".[dev]"
|
|
45
|
+
- run: pytest --cov=limno --cov-report=term-missing
|
|
46
|
+
|
|
47
|
+
build:
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
- uses: actions/setup-python@v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: "3.12"
|
|
54
|
+
- run: pip install build twine
|
|
55
|
+
- run: python -m build
|
|
56
|
+
- run: twine check dist/*
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
pypi:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
limno-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Read the Docs configuration, see https://docs.readthedocs.io/en/stable/config-file/v2.html
|
|
2
|
+
version: 2
|
|
3
|
+
|
|
4
|
+
build:
|
|
5
|
+
os: ubuntu-24.04
|
|
6
|
+
tools:
|
|
7
|
+
python: "3.12"
|
|
8
|
+
|
|
9
|
+
sphinx:
|
|
10
|
+
configuration: docs/conf.py
|
|
11
|
+
fail_on_warning: true
|
|
12
|
+
|
|
13
|
+
python:
|
|
14
|
+
install:
|
|
15
|
+
- method: pip
|
|
16
|
+
path: .
|
|
17
|
+
extras:
|
|
18
|
+
- docs
|
limno-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
* Set up a virtual environment, then run `pip install -e ".[dev,docs]"` to install development
|
|
4
|
+
dependencies.
|
|
5
|
+
- Add `pip install -e ".[river]" matplotlib pandas jupyter` to run the notebooks.
|
|
6
|
+
* Run doctests and unit tests with `pytest -q`. This runs `tests` and the doctests in `src`.
|
|
7
|
+
* Run lint and type checks with `ruff check .` and `mypy src`.
|
|
8
|
+
* Check notebooks execute with
|
|
9
|
+
`jupyter nbconvert --to notebook --execute --stdout notebooks/*.ipynb > /dev/null`.
|
|
10
|
+
* Build documentation with `sphinx-build -W -b html docs docs/_build/html`.
|
|
11
|
+
* Clean documentation with `rm -rf docs/_build`.
|
|
12
|
+
* MUST run formatter `ruff format .` before committing code.
|
|
13
|
+
* MUST ask the user before pushing to GitHub.
|
|
14
|
+
* SHOULD add user-facing changes to the `Unreleased` section of `CHANGELOG.md`.
|
|
15
|
+
|
|
16
|
+
## Design
|
|
17
|
+
|
|
18
|
+
* Explainers MUST rely on the protocols in `limno.base`, not on a specific library. River models
|
|
19
|
+
and metrics satisfy them as they are. Other libraries get an adapter.
|
|
20
|
+
* Heavy dependencies MUST be optional extras, imported inside the function that needs them, so
|
|
21
|
+
that `import limno` works without them.
|
|
22
|
+
|
|
23
|
+
## Commit messages
|
|
24
|
+
|
|
25
|
+
* SHOULD use conventional commit messages. You MAY introduce breaking changes, but MUST
|
|
26
|
+
NOT include `!` or `BREAKING CHANGE` in the commit message since we are pre v1.0.0.
|
|
27
|
+
* MUST NOT add `Co-Authored-By: Claude <noreply@anthropic.com>` (or similar) to commit messages.
|
|
28
|
+
* MUST add `Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2] ...` to the end of
|
|
29
|
+
commit messages and PR descriptions.
|
|
30
|
+
* `AGENT_NAME` is the name of the harness (/tool/framework)
|
|
31
|
+
* `MODEL_VERSION` is the specific model version. SHOULD be as specific as possible
|
|
32
|
+
including model family, version, and size.
|
|
33
|
+
* `[TOOL1] [TOOL2]` are optional agent developer tools or MCP. SHOULD NOT include
|
|
34
|
+
basic developer tools.
|
|
35
|
+
* Example: `Assisted-by: claude-code:claude-opus-5.5 github-mcp-server`
|
|
36
|
+
* Example: `Assisted-by: copilot:gemini-3.7-flash`
|
|
37
|
+
|
|
38
|
+
## Documentation
|
|
39
|
+
|
|
40
|
+
* SHOULD use simplified technical english in documentation and comments.
|
|
41
|
+
* SHOULD NOT use long words where a short one will do.
|
|
42
|
+
* SHOULD use everyday words except where technical terms are required.
|
|
43
|
+
* If it is possible to cut a word out, you SHOULD cut it out.
|
|
44
|
+
* SHOULD avoid complex sentence structures.
|
|
45
|
+
* Consider using commas or parenthesis over em-dash or removing the clause entirely.
|
|
46
|
+
* Docstrings use the NumPy style, with code between single backticks.
|
limno-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## v0.1.0 (2026-11-11)
|
|
10
|
+
|
|
11
|
+
### Feature
|
|
12
|
+
|
|
13
|
+
* Add `lm.base` with the `Model`, `Metric` and `Tracker` protocols, and the `Explainer`, `ImportanceExplainer`, `Storage` and `Imputer` base classes
|
|
14
|
+
|
|
15
|
+
* Add `lm.importance.PFI`, the incremental permutation feature importance (iPFI) of Fumagalli et al. (2023)
|
|
16
|
+
|
|
17
|
+
* Add `lm.importance.SAGE`, the interventional version of incremental SAGE (iSAGE) of Muschalik et al. (2023)
|
|
18
|
+
|
|
19
|
+
* Add `max_age` to `lm.importance.PFI`, which hides features that have stopped appearing
|
|
20
|
+
|
|
21
|
+
* Add `groups` to `lm.importance.PFI` and `lm.importance.SAGE`, which treats some features as one
|
|
22
|
+
|
|
23
|
+
* Add `lm.multioutput` with `PerOutput`, which gives the importances of each output of a model
|
|
24
|
+
|
|
25
|
+
* Add `lm.storage` with `UniformReservoir` and `GeometricReservoir`
|
|
26
|
+
|
|
27
|
+
* Add `lm.imputer` with `Marginal`
|
|
28
|
+
|
|
29
|
+
* Add `lm.tracker` with `Mean` and `EWMean`
|
|
30
|
+
|
|
31
|
+
### Documentation
|
|
32
|
+
|
|
33
|
+
* Add a notebook on how `lm.importance.PFI` works
|
|
34
|
+
|
|
35
|
+
* Add a notebook on how `lm.importance.SAGE` works
|
limno-0.1.0/CITATION.cff
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use limno in your research, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "limno: explainable AI for data streams and continual learning"
|
|
5
|
+
abstract: >-
|
|
6
|
+
limno is a Python library to explain models that learn from data streams, one
|
|
7
|
+
instance at a time. It follows the conventions of River.
|
|
8
|
+
authors:
|
|
9
|
+
- family-names: "da Costa Garcia"
|
|
10
|
+
given-names: "Vitor"
|
|
11
|
+
email: vitorcostagarcia2006@gmail.com
|
|
12
|
+
orcid: "https://orcid.org/0009-0009-0772-8356"
|
|
13
|
+
version: 0.1.0
|
|
14
|
+
date-released: 2026-11-11
|
|
15
|
+
license: BSD-3-Clause
|
|
16
|
+
repository-code: "https://github.com/vitor-costa-garcia/limno"
|
|
17
|
+
keywords:
|
|
18
|
+
- explainable AI
|
|
19
|
+
- data streams
|
|
20
|
+
- online learning
|
|
21
|
+
- incremental learning
|
|
22
|
+
- continual learning
|
|
23
|
+
- river
|
limno-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Vitor
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
limno-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: limno
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Explainable AI for data streams and continual learning.
|
|
5
|
+
Project-URL: Homepage, https://github.com/vitor-costa-garcia/limno
|
|
6
|
+
Project-URL: Issues, https://github.com/vitor-costa-garcia/limno/issues
|
|
7
|
+
Author-email: Vitor da Costa Garcia <vitorcostagarcia2006@gmail.com>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: continual-learning,data-streams,explainable-ai,incremental-learning,online-learning,river,xai
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
18
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
20
|
+
Requires-Dist: river>=0.21; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
22
|
+
Provides-Extra: docs
|
|
23
|
+
Requires-Dist: furo; extra == 'docs'
|
|
24
|
+
Requires-Dist: myst-parser; extra == 'docs'
|
|
25
|
+
Requires-Dist: sphinx; extra == 'docs'
|
|
26
|
+
Provides-Extra: river
|
|
27
|
+
Requires-Dist: river>=0.21; extra == 'river'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# limno
|
|
31
|
+
|
|
32
|
+
[](https://github.com/vitor-costa-garcia/limno/actions/workflows/ci.yml)
|
|
33
|
+
|
|
34
|
+
**Explainable AI for data streams and continual learning.**
|
|
35
|
+
|
|
36
|
+
> limno is in early development: the API may change.
|
|
37
|
+
|
|
38
|
+
## What is this?
|
|
39
|
+
|
|
40
|
+
A model that learns from a stream keeps changing, and so do the reasons behind its predictions.
|
|
41
|
+
Most explanation tools assume a fixed model and a fixed dataset, so they do not fit this setting.
|
|
42
|
+
limno provides explanations that are computed one instance at a time and that follow the model as
|
|
43
|
+
it learns. Limnology is the study of inland waters, and limno looks at what goes on inside a
|
|
44
|
+
stream.
|
|
45
|
+
|
|
46
|
+
limno follows [River](https://riverml.xyz)'s conventions and works with River's models, pipelines,
|
|
47
|
+
metrics and statistics as they are. It complements River rather than replacing it. Other libraries,
|
|
48
|
+
such as [CapyMOA](https://capymoa.org), are not supported yet, but explainers do not depend on
|
|
49
|
+
River, so an adapter can add them later.
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Incremental permutation feature importance** (`lm.importance.PFI`), from
|
|
54
|
+
[Fumagalli et al. (2023)](https://doi.org/10.1007/s10994-023-06385-y). It shows how much a model
|
|
55
|
+
relies on each feature, as the stream goes on.
|
|
56
|
+
- **Incremental SAGE** (`lm.importance.SAGE`), from
|
|
57
|
+
[Muschalik et al. (2023)](https://doi.org/10.1007/978-3-031-43418-1_26). Its values add up to the
|
|
58
|
+
drop in loss between predicting the mean and using the model.
|
|
59
|
+
- **Groups of features** (`groups=`), to measure features that only make sense together as one.
|
|
60
|
+
- **Models with many outputs** (`lm.multioutput.PerOutput`), to see which features each output
|
|
61
|
+
relies on.
|
|
62
|
+
- **River metrics as the loss.** Whether the model is asked for labels or probabilities depends on
|
|
63
|
+
the metric, as in River.
|
|
64
|
+
- **Separate pieces** that can be swapped:
|
|
65
|
+
- Storages (`lm.storage`) keep past instances: `UniformReservoir` and `GeometricReservoir`.
|
|
66
|
+
- Imputers (`lm.imputer`) replace feature values: `Marginal`.
|
|
67
|
+
- Trackers (`lm.tracker`) keep running values: `Mean`, `EWMean`, or any of `river.stats`.
|
|
68
|
+
- **Features can appear and disappear** along the stream, with no list of names to give upfront. A
|
|
69
|
+
feature that stops appearing is hidden after `max_age` instances.
|
|
70
|
+
- **Reproducible runs** with a `seed`.
|
|
71
|
+
- **A base class for your own explainers** (`lm.base.Explainer` and
|
|
72
|
+
`lm.base.ImportanceExplainer`).
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
pip install "limno[river]"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The `river` extra installs River. limno itself has no required dependencies, so
|
|
81
|
+
`pip install limno` is enough for models and metrics from elsewhere.
|
|
82
|
+
|
|
83
|
+
## Quickstart
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from river import datasets, linear_model, metrics, preprocessing
|
|
87
|
+
|
|
88
|
+
import limno as lm
|
|
89
|
+
|
|
90
|
+
model = preprocessing.StandardScaler() | linear_model.LogisticRegression()
|
|
91
|
+
explainer = lm.importance.PFI(model, metrics.LogLoss(), seed=42)
|
|
92
|
+
|
|
93
|
+
for x, y in datasets.Phishing():
|
|
94
|
+
explainer.learn_one(x, y) # before the model learns, so the instance is new to it
|
|
95
|
+
model.learn_one(x, y)
|
|
96
|
+
|
|
97
|
+
explainer.importances
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
{'empty_server_form_handler': 0.177, 'popup_window': 0.11, 'https': 0.106, ...}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
A positive value means that the model does better with the feature, and a value close to zero that
|
|
105
|
+
it does not rely on it. The explainer never updates the model.
|
|
106
|
+
|
|
107
|
+
## Notebooks
|
|
108
|
+
|
|
109
|
+
The [notebooks](https://github.com/vitor-costa-garcia/limno/tree/main/notebooks) show limno in use
|
|
110
|
+
with River. [How incremental PFI works](https://github.com/vitor-costa-garcia/limno/blob/main/notebooks/01_how_pfi_works.ipynb)
|
|
111
|
+
and [How incremental SAGE works](https://github.com/vitor-costa-garcia/limno/blob/main/notebooks/02_how_sage_works.ipynb)
|
|
112
|
+
explain the methods step by step.
|
|
113
|
+
|
|
114
|
+
## Contributing and feedback
|
|
115
|
+
|
|
116
|
+
Ideas, use cases and criticism are welcome through
|
|
117
|
+
[GitHub issues](https://github.com/vitor-costa-garcia/limno/issues).
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
BSD 3-Clause. See [LICENSE](https://github.com/vitor-costa-garcia/limno/blob/main/LICENSE).
|
limno-0.1.0/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# limno
|
|
2
|
+
|
|
3
|
+
[](https://github.com/vitor-costa-garcia/limno/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
**Explainable AI for data streams and continual learning.**
|
|
6
|
+
|
|
7
|
+
> limno is in early development: the API may change.
|
|
8
|
+
|
|
9
|
+
## What is this?
|
|
10
|
+
|
|
11
|
+
A model that learns from a stream keeps changing, and so do the reasons behind its predictions.
|
|
12
|
+
Most explanation tools assume a fixed model and a fixed dataset, so they do not fit this setting.
|
|
13
|
+
limno provides explanations that are computed one instance at a time and that follow the model as
|
|
14
|
+
it learns. Limnology is the study of inland waters, and limno looks at what goes on inside a
|
|
15
|
+
stream.
|
|
16
|
+
|
|
17
|
+
limno follows [River](https://riverml.xyz)'s conventions and works with River's models, pipelines,
|
|
18
|
+
metrics and statistics as they are. It complements River rather than replacing it. Other libraries,
|
|
19
|
+
such as [CapyMOA](https://capymoa.org), are not supported yet, but explainers do not depend on
|
|
20
|
+
River, so an adapter can add them later.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Incremental permutation feature importance** (`lm.importance.PFI`), from
|
|
25
|
+
[Fumagalli et al. (2023)](https://doi.org/10.1007/s10994-023-06385-y). It shows how much a model
|
|
26
|
+
relies on each feature, as the stream goes on.
|
|
27
|
+
- **Incremental SAGE** (`lm.importance.SAGE`), from
|
|
28
|
+
[Muschalik et al. (2023)](https://doi.org/10.1007/978-3-031-43418-1_26). Its values add up to the
|
|
29
|
+
drop in loss between predicting the mean and using the model.
|
|
30
|
+
- **Groups of features** (`groups=`), to measure features that only make sense together as one.
|
|
31
|
+
- **Models with many outputs** (`lm.multioutput.PerOutput`), to see which features each output
|
|
32
|
+
relies on.
|
|
33
|
+
- **River metrics as the loss.** Whether the model is asked for labels or probabilities depends on
|
|
34
|
+
the metric, as in River.
|
|
35
|
+
- **Separate pieces** that can be swapped:
|
|
36
|
+
- Storages (`lm.storage`) keep past instances: `UniformReservoir` and `GeometricReservoir`.
|
|
37
|
+
- Imputers (`lm.imputer`) replace feature values: `Marginal`.
|
|
38
|
+
- Trackers (`lm.tracker`) keep running values: `Mean`, `EWMean`, or any of `river.stats`.
|
|
39
|
+
- **Features can appear and disappear** along the stream, with no list of names to give upfront. A
|
|
40
|
+
feature that stops appearing is hidden after `max_age` instances.
|
|
41
|
+
- **Reproducible runs** with a `seed`.
|
|
42
|
+
- **A base class for your own explainers** (`lm.base.Explainer` and
|
|
43
|
+
`lm.base.ImportanceExplainer`).
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install "limno[river]"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The `river` extra installs River. limno itself has no required dependencies, so
|
|
52
|
+
`pip install limno` is enough for models and metrics from elsewhere.
|
|
53
|
+
|
|
54
|
+
## Quickstart
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from river import datasets, linear_model, metrics, preprocessing
|
|
58
|
+
|
|
59
|
+
import limno as lm
|
|
60
|
+
|
|
61
|
+
model = preprocessing.StandardScaler() | linear_model.LogisticRegression()
|
|
62
|
+
explainer = lm.importance.PFI(model, metrics.LogLoss(), seed=42)
|
|
63
|
+
|
|
64
|
+
for x, y in datasets.Phishing():
|
|
65
|
+
explainer.learn_one(x, y) # before the model learns, so the instance is new to it
|
|
66
|
+
model.learn_one(x, y)
|
|
67
|
+
|
|
68
|
+
explainer.importances
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
{'empty_server_form_handler': 0.177, 'popup_window': 0.11, 'https': 0.106, ...}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
A positive value means that the model does better with the feature, and a value close to zero that
|
|
76
|
+
it does not rely on it. The explainer never updates the model.
|
|
77
|
+
|
|
78
|
+
## Notebooks
|
|
79
|
+
|
|
80
|
+
The [notebooks](https://github.com/vitor-costa-garcia/limno/tree/main/notebooks) show limno in use
|
|
81
|
+
with River. [How incremental PFI works](https://github.com/vitor-costa-garcia/limno/blob/main/notebooks/01_how_pfi_works.ipynb)
|
|
82
|
+
and [How incremental SAGE works](https://github.com/vitor-costa-garcia/limno/blob/main/notebooks/02_how_sage_works.ipynb)
|
|
83
|
+
explain the methods step by step.
|
|
84
|
+
|
|
85
|
+
## Contributing and feedback
|
|
86
|
+
|
|
87
|
+
Ideas, use cases and criticism are welcome through
|
|
88
|
+
[GitHub issues](https://github.com/vitor-costa-garcia/limno/issues).
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
BSD 3-Clause. See [LICENSE](https://github.com/vitor-costa-garcia/limno/blob/main/LICENSE).
|
limno-0.1.0/docs/conf.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Sphinx configuration."""
|
|
2
|
+
|
|
3
|
+
import limno
|
|
4
|
+
|
|
5
|
+
project = "limno"
|
|
6
|
+
author = "Vitor da Costa Garcia"
|
|
7
|
+
copyright = f"2026, {author}"
|
|
8
|
+
release = limno.__version__
|
|
9
|
+
version = ".".join(release.split(".")[:2])
|
|
10
|
+
|
|
11
|
+
extensions = [
|
|
12
|
+
"myst_parser",
|
|
13
|
+
"sphinx.ext.autodoc",
|
|
14
|
+
"sphinx.ext.intersphinx",
|
|
15
|
+
"sphinx.ext.napoleon",
|
|
16
|
+
"sphinx.ext.viewcode",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
exclude_patterns = ["_build"]
|
|
20
|
+
|
|
21
|
+
# The docstrings write code between single backticks, as in Markdown
|
|
22
|
+
default_role = "py:obj"
|
|
23
|
+
|
|
24
|
+
autodoc_default_options = {"members": True, "show-inheritance": True}
|
|
25
|
+
autodoc_member_order = "bysource"
|
|
26
|
+
autodoc_typehints = "description"
|
|
27
|
+
|
|
28
|
+
napoleon_google_docstring = False
|
|
29
|
+
napoleon_numpy_docstring = True
|
|
30
|
+
|
|
31
|
+
intersphinx_mapping = {
|
|
32
|
+
"python": ("https://docs.python.org/3", None),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
html_theme = "furo"
|
|
36
|
+
html_title = "limno"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# limno
|
|
2
|
+
|
|
3
|
+
**Explainable AI for data streams and continual learning.**
|
|
4
|
+
|
|
5
|
+
```{note}
|
|
6
|
+
limno is in early development: the API may change.
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
A model that learns from a stream keeps changing, and so do the reasons behind its predictions.
|
|
10
|
+
limno provides explanations that are computed one instance at a time and that follow the model as
|
|
11
|
+
it learns. It follows [River](https://riverml.xyz)'s conventions and works with River's models,
|
|
12
|
+
pipelines, metrics and statistics as they are.
|
|
13
|
+
|
|
14
|
+
```{toctree}
|
|
15
|
+
:maxdepth: 2
|
|
16
|
+
|
|
17
|
+
installation
|
|
18
|
+
quickstart
|
|
19
|
+
api/index
|
|
20
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
pip install "limno[river]"
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
The `river` extra installs River 0.21 or later. limno itself has no required dependencies, so
|
|
8
|
+
`pip install limno` is enough for models and metrics from elsewhere.
|
|
9
|
+
|
|
10
|
+
To work on limno, install it from a clone:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install -e ".[dev,docs]"
|
|
14
|
+
```
|