Metadata-Version: 2.4
Name: nikodym
Version: 0.9.0
Summary: Librería de riesgo de crédito: scoring, ML, provisiones CMF e IFRS 9/ECL, forward-looking y stress testing.
Project-URL: Homepage, https://github.com/nexolabs-gh/nikodym
Project-URL: Source, https://github.com/nexolabs-gh/nikodym
Project-URL: Documentation, https://github.com/nexolabs-gh/nikodym#readme
Project-URL: Changelog, https://github.com/nexolabs-gh/nikodym/blob/main/CHANGELOG.md
Author-email: Nikodym <admin@nxlabs.cl>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: cmf,credit-risk,ecl,ifrs9,provisioning,scorecard
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: jinja2>=3.1
Requires-Dist: joblib>=1.3
Requires-Dist: numpy>=1.22
Requires-Dist: pandas>=2.0
Requires-Dist: pandera>=0.24
Requires-Dist: pyarrow>=14
Requires-Dist: pydantic>=2.5
Requires-Dist: pyyaml>=6.0
Provides-Extra: ai
Requires-Dist: anthropic>=0.40; extra == 'ai'
Provides-Extra: all
Requires-Dist: anthropic>=0.40; extra == 'all'
Requires-Dist: catboost>=1.2; extra == 'all'
Requires-Dist: fastapi>=0.110; extra == 'all'
Requires-Dist: hydra-core>=1.3; extra == 'all'
Requires-Dist: lifelines>=0.28; extra == 'all'
Requires-Dist: lightgbm>=4.0; extra == 'all'
Requires-Dist: llvmlite>=0.43; extra == 'all'
Requires-Dist: matplotlib>=3.7; extra == 'all'
Requires-Dist: mlflow>=2.10; extra == 'all'
Requires-Dist: numba>=0.60; extra == 'all'
Requires-Dist: omegaconf>=2.3; extra == 'all'
Requires-Dist: openpyxl>=3.1; extra == 'all'
Requires-Dist: optbinning>=0.19; extra == 'all'
Requires-Dist: optuna>=3.5; extra == 'all'
Requires-Dist: plotly>=5.0; extra == 'all'
Requires-Dist: pmdarima>=2.0; extra == 'all'
Requires-Dist: polars>=0.20; extra == 'all'
Requires-Dist: python-multipart>=0.0.9; extra == 'all'
Requires-Dist: scikit-learn>=1.6; extra == 'all'
Requires-Dist: scipy>=1.10; extra == 'all'
Requires-Dist: shap>=0.44; extra == 'all'
Requires-Dist: statsmodels>=0.14; extra == 'all'
Requires-Dist: uvicorn>=0.29; extra == 'all'
Requires-Dist: xgboost>=2.0; extra == 'all'
Provides-Extra: catboost
Requires-Dist: catboost>=1.2; extra == 'catboost'
Requires-Dist: scikit-learn>=1.6; extra == 'catboost'
Provides-Extra: excel
Requires-Dist: openpyxl>=3.1; extra == 'excel'
Provides-Extra: explain
Requires-Dist: llvmlite>=0.43; extra == 'explain'
Requires-Dist: matplotlib>=3.7; extra == 'explain'
Requires-Dist: numba>=0.60; extra == 'explain'
Requires-Dist: shap>=0.44; extra == 'explain'
Provides-Extra: forecasting
Requires-Dist: pmdarima>=2.0; extra == 'forecasting'
Requires-Dist: statsmodels>=0.14; extra == 'forecasting'
Provides-Extra: lightgbm
Requires-Dist: lightgbm>=4.0; extra == 'lightgbm'
Requires-Dist: scikit-learn>=1.6; extra == 'lightgbm'
Provides-Extra: ml
Requires-Dist: scikit-learn>=1.6; extra == 'ml'
Provides-Extra: polars
Requires-Dist: polars>=0.20; extra == 'polars'
Provides-Extra: report
Requires-Dist: matplotlib>=3.7; extra == 'report'
Requires-Dist: plotly>=5.0; extra == 'report'
Provides-Extra: scoring
Requires-Dist: optbinning>=0.19; extra == 'scoring'
Requires-Dist: scikit-learn>=1.6; extra == 'scoring'
Requires-Dist: scipy>=1.10; extra == 'scoring'
Requires-Dist: statsmodels>=0.14; extra == 'scoring'
Provides-Extra: survival
Requires-Dist: lifelines>=0.28; extra == 'survival'
Provides-Extra: sweep
Requires-Dist: hydra-core>=1.3; extra == 'sweep'
Requires-Dist: omegaconf>=2.3; extra == 'sweep'
Provides-Extra: tracking
Requires-Dist: mlflow>=2.10; extra == 'tracking'
Provides-Extra: tuning
Requires-Dist: optuna>=3.5; extra == 'tuning'
Provides-Extra: ui
Requires-Dist: fastapi>=0.110; extra == 'ui'
Requires-Dist: openpyxl>=3.1; extra == 'ui'
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
Requires-Dist: uvicorn>=0.29; extra == 'ui'
Provides-Extra: xgboost
Requires-Dist: scikit-learn>=1.6; extra == 'xgboost'
Requires-Dist: xgboost>=2.0; extra == 'xgboost'
Description-Content-Type: text/markdown

# Nikodym RiskLib

[![PyPI](https://img.shields.io/pypi/v/nikodym.svg)](https://pypi.org/project/nikodym/)
[![Python](https://img.shields.io/pypi/pyversions/nikodym.svg)](https://pypi.org/project/nikodym/)
[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
[![CI](https://github.com/nexolabs-gh/nikodym/actions/workflows/ci.yml/badge.svg)](https://github.com/nexolabs-gh/nikodym/actions/workflows/ci.yml)

Librería Python **open-source (Apache-2.0)** de riesgo de crédito **integral**:
scoring/scorecards, backends ML, provisiones **CMF (Chile)** e **IFRS 9/ECL**, forward-looking
y stress testing. Todo en un motor **reproducible por construcción** y con gobernanza
(model card + audit-trail) automática. Paquete: `nikodym`.

> **Estado: pre-1.0 (0.9.x).** El motor V1 está completo y verde; la API pública sigue
> versionada como **0.x honesto** (SemVer): puede cambiar hasta la 1.0. Las superficies que aún
> crecen (resultados/overlay/métricas/orquestación) están marcadas como experimentales.

## Qué hace

- **Scorecard (F1)**: binning/WoE con monotonía (optbinning), selección, regresión logística,
  scorecard escalado, calibración y métricas de desempeño (AUC/KS/Gini) y estabilidad (PSI/CSI).
- **Backends ML (F2)**: XGBoost, LightGBM, CatBoost y tuning (Optuna) como *extras* selectivos,
  con explicabilidad (SHAP) opcional.
- **Provisiones**: motores **CMF (Chile)** e **IFRS 9/ECL** separados; la provisión es el
  **máximo** de ambos (piso prudencial).
- **Forward-looking & stress testing**: proyección macroeconómica y escenarios.
- **Reproducibilidad total**: `(datos + config + semilla) → resultado idéntico`, con *lineage
  bundle* (git SHA + hash de datos + config + semilla + `uv.lock`) en cada corrida.

## Instalación

```bash
pip install nikodym                 # núcleo base (config, Study, lineage)
pip install 'nikodym[scoring]'      # MVP scorecard (optbinning + statsmodels + sklearn>=1.6)
pip install 'nikodym[all]'          # todo lo redistribuible (sin copyleft)
```

Requiere Python ≥ 3.11. El núcleo base es liviano: `import nikodym` **no** arrastra el stack ML;
los backends pesados viven tras *extras* opcionales con import perezoso.

## Quickstart

El experimento es un `NikodymConfig` declarativo; `nikodym.run(config)` lo ejecuta de extremo a
extremo (binning → selección → modelo → scorecard → calibración → desempeño → estabilidad) y
devuelve un `Study` reproducible. Este ejemplo usa el **preset estándar F1** sobre un dataset
sintético de consumo, así corre sin rellenar ningún campo:

```python
from pathlib import Path
from tempfile import mkdtemp

import nikodym
from nikodym.core.config import NikodymConfig
from nikodym.ui.datasets import materialize
from nikodym.ui.presets import standard_preset

# 1. Materializa el dataset sintético de consumo (determinista) en un workdir temporal.
workdir = Path(mkdtemp(prefix="nikodym-quickstart-"))
preset = standard_preset()
data_path = materialize(preset["dataset_id"], workdir=workdir)

# 2. Toma el config F1 curado y apúntalo al archivo de datos recién materializado.
cfg_dict = preset["config"]
cfg_dict["data"]["load"]["source"] = str(data_path)
config = NikodymConfig.model_validate(cfg_dict)

# 3. Ejecuta la corrida completa y verifica el estado.
study = nikodym.run(config)
assert study.run_context.status == "done"

# 4. Accede a los resultados namespaced por dominio/clave.
scorecard = study.artifacts.get("scorecard", "scorecard")             # tabla del scorecard
metrics = study.artifacts.get("performance", "discriminant_metrics")  # AUC/KS/Gini por partición
print(metrics)
```

`nikodym.run` es *fail-loud pero no explosivo*: ante un fallo devuelve el `Study` **parcial** con
`study.run_context.status == "failed"` (el error vive en el audit-trail y el lineage, no se
silencia). El consumidor por código **debe** chequear `study.run_context.status` antes de usar los
resultados.

## Principios de diseño

- **Reproducibilidad total**: misma entrada → resultado byte-idéntico, con lineage completo.
- **Gobernanza por construcción** (SR 11-7): *model card* y *audit-trail* automáticos.
- **Config declarativo** (Pydantic v2): *el config ES el experimento*.
- **Núcleo liviano**: los backends pesados van tras *extras* con import perezoso.
- **CMF ≠ IFRS 9**: dos motores separados; la provisión es el máximo (piso prudencial).

## Documentación

Guía completa (conceptos, referencia de `run`/`Study`/`NikodymConfig`) en el
[sitio de documentación](https://github.com/nexolabs-gh/nikodym#readme). El `CHANGELOG.md`
registra los cambios por versión.

## Desarrollo

El proyecto usa [uv](https://docs.astral.sh/uv/) + hatchling, con layout `src/`.

```bash
uv sync                              # entorno completo (grupo dev: test/lint/docs)
uv run ruff check . && uv run ruff format --check .
uv run mypy                          # type-check estricto de todo el paquete
uv run pytest                        # suite de tests
```

## Licencia

[Apache-2.0](LICENSE). Sin dependencias copyleft (GPL/LGPL/AGPL) en el wheel.
