Skip to main content

bayesrisk

PyPI Python License: Apache-2.0 CI

Librería Python open-source (Apache-2.0) de riesgo de crédito integral: PD (scorecards, backends ML, survival), LGD y EAD, validación de modelos, provisiones IFRS 9/ECL, forward-looking y stress testing, con informe reproducible y su lineage. Todo en un motor reproducible por construcción, con lineage en cada corrida y una gobernanza —audit-trail y ficha del modelo (model card)— que se enciende con una declaración de propósito. Paquete: bayesrisk.

Antes se llamaba nikodym. Desde la 2.0.0 la librería se llama bayesrisk, con los mismos resultados bit a bit que nikodym 1.20.0. Migrar es cambiar una línea —import bayesrisk—: ver Migrar desde nikodym.

Los estándares comunes —Basilea, IFRS 9— van en el motor. La normativa local de cada jurisdicción se aterriza encima, y hay un caso de referencia implementado que muestra cómo: Aterrizar una norma local.

Estado: 2.x (estable). El pipeline de validación de scorecard (F1) es API estable (SemVer 2.x): no rompe hasta un 3.0. Las superficies que aún crecen —modelado ML, provisiones, forward-looking, y los contratos transversales de resultados/métricas/orquestación— siguen marcadas como experimentales (fuera de la garantía SemVer 2.x).

Qué hace

Los seis dominios calculan hoy: son motores deterministas, sin stubs, con más de 500 tests sobre los tres que no tienen interfaz (más de 4.900 en la suite completa). Lo que los separa no es "hecho / no hecho", sino superficie (¿tiene UI, preset y capítulo en el informe, o hay que escribir el config en Python?) y garantía de API (¿congelada bajo SemVer 2.x, o experimental?). El único comando del paquete es bayesrisk-ui, que levanta la interfaz: no hay CLI que corra estos dominios.

Dominio Superficie Garantía
Scorecard (F1) — binning/WoE monotónico (optbinning), selección (IV/VIF), regresión logística, scorecard escalado (PDO/offset), calibración, desempeño (AUC/KS/Gini) y estabilidad (PSI/CSI) UI, preset e informe estable (SemVer 2.x)
Provisiones — IFRS 9/ECL y método interno (exposición por la tasa de pérdida del grupo, descompuesta en PD · LGD o provista directamente; jurisdiccionalmente neutro); la orquestación compara dos fuentes y aplica la regla declarada. La norma local se monta encima: caso de referencia UI, preset e informe experimental
Stress testing — escenarios adversos, shocks macro en escala logit, sensibilidad y reverse stress por bisección Python experimental
Markov — matrices de transición (cohorte/duración), Chapman-Kolmogorov, Aalen-Johansen, term-structure de PD Python experimental
Forward-looking — ARIMA/auto-ARIMA, VAR/VECM, Ljung-Box y modelos satélite macro → PD/LGD Python experimental
Survival — Kaplan-Meier, Cox/AFT y hazard discreto sobre datos censurados UI, preset e informe experimental
  • Backends ML (F2): XGBoost, LightGBM, CatBoost y tuning (Optuna) como extras selectivos, con explicabilidad (SHAP) opcional.
  • No hace (por si lo estás buscando): roll rates, curvas de cosecha/vintage, ni una CLI que ejecute pipelines desde la terminal — el comando bayesrisk-ui levanta la interfaz, no corre nada.
  • Informe de validación, no un log: cada corrida produce un documento con portada, resumen ejecutivo, metodología (redactada con los parámetros que realmente se usaron), resultados, conclusiones y anexos técnicos. Sale en HTML y PDF, y también como base editable (.qmd de Quarto o .docx de Word) para que escribas tu documentación encima: los capítulos que solo puede escribir un humano (contexto de la cartera, conclusión que se firma) vienen como placeholders con guía, nunca inventados.
  • Reproducibilidad total: (datos + config + semilla) → resultado idéntico, con lineage bundle (git SHA, estado del working tree, hash del contenido de los datos, config_hash, semilla raíz, hash del uv.lock con el que se construyó el paquete y versiones de las librerías) en cada corrida.

Tus datos no salen de tu infraestructura

bayesrisk es una librería, no un servicio: se instala con pip y corre donde tú la ejecutes —tu notebook, tu servidor, tu clúster, dentro de tu red—. Para una institución financiera esto suele importar más que cualquier métrica:

  • Sin telemetría. El paquete no reporta uso, ni versiones, ni nada. No hay código de analítica.
  • Sin llamadas de red en el cálculo. El pipeline no abre conexiones por sí solo: las cifras se computan en tu proceso, con tus datos, y los artefactos se escriben en el workdir que declaras.
  • Sin dependencias de un servicio nuestro. No hay una API que tenga que estar arriba para que el motor funcione, ni licencia que validar contra un servidor. Si Bayes Advisory desaparece mañana, tu corrida de pasado mañana sigue dando el mismo resultado.
  • Las dos salidas posibles son tuyas y opcionales: la narración por IA (apagada por defecto, con tu clave y tu proveedor; la prosa del informe es determinista y no la escribe la IA) y el registro de experimentos MLflow, que por defecto escribe en un directorio local. Detalle en SECURITY.md.

Y como es Apache-2.0, puedes auditar el código, forkearlo y adaptarlo sin pedirnos permiso.

Instalación

pip install bayesrisk                 # núcleo base (config, Study, lineage)
pip install 'bayesrisk[scoring]'      # MVP scorecard (optbinning + statsmodels + sklearn>=1.6)
pip install 'bayesrisk[ui]'           # interfaz gráfica local, lista para correr (ver más abajo)
pip install 'bayesrisk[all]'          # todo lo redistribuible (sin copyleft)

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

El informe en PDF necesita librerías del sistema

El informe sale en HTML con la instalación base, y en Word (.docx) con bayesrisk[all]. El PDF es el único formato con un requisito extra, y conviene saberlo antes de necesitarlo:

pip install 'bayesrisk[pdf]'          # NO está incluido en [all] — ver nota de licencia abajo

bayesrisk[pdf] instala WeasyPrint, pero WeasyPrint no es Python puro: carga Pango (≥ 1.44), HarfBuzz y libffi desde el sistema operativo, y pip no puede instalarlas. Hay que agregarlas por fuera (documentación oficial de WeasyPrint):

Sistema Comando
macOS brew install weasyprint
Debian ≥ 11 / Ubuntu ≥ 20.04 apt install libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz-subset0
Windows MSYS2: pacman -S mingw-w64-x86_64-pango

Si faltan, no se rompe nada: la corrida termina igual, el informe se emite en HTML y un RuntimeWarning dice exactamente cuál de los dos requisitos falta —el paquete o las librerías del sistema—. Si prefieres que la ausencia sea un error en vez de una degradación (recomendable en un pipeline de producción que promete PDF), pon report.pdf.fail_if_unavailable = True en el config.

En macOS con Homebrew en /opt/homebrew (Apple Silicon), el enlazador puede no encontrar las librerías aunque brew las haya instalado. Se resuelve exportando DYLD_FALLBACK_LIBRARY_PATH=/opt/homebrew/lib.

Por qué [pdf] no entra en [all]: WeasyPrint arrastra Pyphen, de tri-licencia con GPL. El meta-extra [all] se mantiene libre de copyleft para que puedas redistribuir un cierre completo sin revisar licencias. El PDF queda a un pip install de distancia, como decisión tuya.

Quickstart

La forma más corta es la puerta guiada bayesrisk.Scorecard (estable bajo SemVer 2.x): datos, qué es «malo», identificador, eje temporal y muestra fuera de tiempo, y run() corre y cuenta cada etapa; está en «Tu primer scorecard en 15 líneas» de la documentación. Debajo, la puerta completa: el experimento es un BayesRiskConfig declarativo; bayesrisk.run(config, run_dir=...) lo ejecuta de extremo a extremo (binning → selección → modelo → scorecard → calibración → desempeño → estabilidad), deja la evidencia de la corrida en run_dir 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:

from pathlib import Path
from tempfile import mkdtemp

import bayesrisk
from bayesrisk.core.config import BayesRiskConfig
from bayesrisk.ui.datasets import materialize
from bayesrisk.ui.presets import standard_preset

# 1. Materializa el dataset sintético de consumo (determinista) en un workdir temporal.
workdir = Path(mkdtemp(prefix="bayesrisk-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 = BayesRiskConfig.model_validate(cfg_dict)

# 3. Ejecuta la corrida completa y verifica el estado ANTES de leer resultados. `run_dir` es
#    donde queda su evidencia: el audit-trail que el preset trae encendido y, si declaras la
#    sección `governance`, la ficha del modelo.
study = bayesrisk.run(config, run_dir=workdir / "corrida")
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)

bayesrisk.run es fail-loud pero no explosivo: ante un fallo devuelve el Study parcial con study.run_context.status == "failed", y el diagnóstico —tipo del error, mensaje del motor y paso que falló— queda en study.run_context.error, sin configurar nada. El consumidor por código debe chequear study.run_context.status antes de usar los resultados.

La misma corrida, sin escribir código

bayesrisk trae una interfaz gráfica local. Son dos comandos:

pip install 'bayesrisk[ui]'
bayesrisk-ui

El segundo levanta la interfaz en http://127.0.0.1:8000 y abre el navegador. Desde ahí eliges un dataset —uno de ejemplo o el tuyo, en CSV, Excel o Parquet—, ajustas la configuración en un formulario, ejecutas y descargas el informe.

No es una demo aparte: es el mismo motor y el mismo BayesRiskConfig. Lo que armas en el formulario se puede exportar a YAML y correr por código, y produce el mismo config_hash. Puedes empezar por la interfaz y terminar en un script, o al revés.

Antes de ejecutar, la interfaz compara tu configuración con las columnas de tu archivo y te dice de una vez cuáles no calzan, con un enlace al campo que hay que corregir. Es un aviso, no un bloqueo: puedes ejecutar igual.

Tres opciones, todas locales:

bayesrisk-ui --port 8123      # otro puerto (por defecto 8000)
bayesrisk-ui --workdir ./runs # dónde guardar corridas y datasets (por defecto .bayesrisk_ui)
bayesrisk-ui --no-open        # no abrir el navegador

Escucha sólo en 127.0.0.1 y no hay forma de cambiarlo: no existe un --host. Tus datos no salen de tu máquina, y la interfaz no es alcanzable desde la red. Cada lanzamiento genera un token propio que nunca se escribe en el log ni en la URL. Detalle en SECURITY.md.

[ui] trae todo lo que el formulario puede ejecutar, no sólo el servidor: el motor del scorecard y el de supervivencia entran con él. Son ~700 MB en disco, y es deliberado — un extra llamado ui que instala la interfaz pero no lo que la interfaz dispara promete algo que no cumple. Quedan fuera el PDF (bayesrisk[pdf]), por licencia, y el backend de lectura polars (bayesrisk[polars]), que es una opción de rendimiento: el resultado no cambia, y si lo eliges sin tenerlo instalado la corrida te lo dice con el comando exacto.

Limitaciones que debes conocer antes de usarlo en serio

El motor las publica de sí mismo —cada fila afectada emite su código de aviso declarado—, así que aquí se dicen igual de claro.

Las dos marcas, y por qué son dos. Cuando un número no sale de un dato real, el resultado lo dice con una de dos marcas, y la diferencia importa: una señala una brecha nuestra —algo que la librería todavía no trae, difirió, o no verificó contra la fuente oficial— y la otra, un dato que sólo tu institución puede fijar: los shocks macro de tu ejercicio de stress, tu taxonomía de estados, tu definición operacional de default. En el segundo caso la marca no confiesa una carencia: deja constancia de que el motor se negó a inventar un supuesto que no le corresponde. Un número que la librería no puede justificar no se rellena con un default cómodo.

Las marcas viajan en la columna warning_codes del resultado. El catálogo completo —qué significa cada código y qué hacer con él— está en Avisos declarados.

  • Los parámetros del caso de referencia no son oficiales, y el caso está congelado. El motor que aterriza la norma chilena (CMF, Cap. B-1) existe como ejemplo de método, no como compromiso de mantenimiento: sus tablas se transcribieron del compendio y no provienen de la CMF ni están validadas por ella —la Comisión no certifica implementaciones de terceros—, así que requieren validación humana contra la norma vigente antes de cualquier uso productivo. Lo que sí está hecho: las tablas se extrajeron del texto oficial el 2026-06-23 y la matriz de consumo (numeral B-1 3.1.3, Circular 2.346/2024) se cotejó celda por celda el 2026-07-14 —sus 16 valores de PI, sus 6 de PDI y el PI de incumplimiento coinciden exactamente—, registrado en docs/normativa_cmf_parametros.md §3. Quedan dos brechas abiertas, y el motor las declara: aforos y haircuts de garantías financieras, y las tablas del RAN 21-10. El alcance, las fechas por matriz y el estado de cada fuente están en Aterrizar una norma local.
  • Las causales de incumplimiento que el motor no puede inferir, las declara el banco. De las tres del numeral B-1 3.2, solo la mora ≥ 90 días sale de los datos; el refinanciamiento para dejar vigente una operación morosa y la reestructuración forzosa hay que entregarlas en la columna is_default. Sin ella, un deudor reestructurado y al día entra a la matriz con una PI de 6,6 % en vez del 100 % que exige la norma — y como la provisión es PI × PDI × exposición, la cifra reportada queda en una fracción de la que corresponde.
  • La EAD de IFRS 9 se despliega constante en el tiempo. El panel longitudinal está diferido; el motor no lo aplana en silencio: cada fila afectada lo declara en sus avisos, y el config rechaza exposure_profile_col en vez de fingir que lo usa.
  • Experimental no es "beta marketinera": todo lo que no sea el pipeline de scorecard puede cambiar de firma dentro de la 2.x, y no está battle-tested en producción.

Principios de diseño

  • Reproducibilidad total: misma entrada → resultado byte-idéntico, con lineage completo.
  • Gobernanza que se enciende, no se inventa: el lineage viaja en toda corrida y el audit-trail en los ejemplos de fábrica; la ficha del modelo se emite cuando tu institución declara el propósito, porque ese dato no lo puede inventar el motor.
  • Config declarativo (Pydantic v2): el config ES el experimento.
  • Núcleo liviano: los backends pesados van tras extras con import perezoso.
  • Una norma local nunca se funde con un estándar contable: son motores separados, nunca uno solo, y la regla que los compara la declara quien la usa. El caso de referencia lo ilustra: la regla del máximo del Capítulo B-1 (Circular N° 2.346) es entre el método estándar y el método interno del banco — no entre ese estándar e IFRS 9, porque el Compendio (Cap. A-2, num. 5) excluye el deterioro de NIIF 9 sobre colocaciones.
  • Lo que falta se declara, no se disimula: un dato ausente sale marcado en el resultado, y la marca dice de quién es —una brecha nuestra, o un parámetro que sólo tu institución puede fijar—; una opción sin motor detrás se rechaza al validar el config, no al final de la corrida.

Documentación

Guía completa (conceptos, referencia de run/Study/BayesRiskConfig) en docs.bayesadvisory.cl. La demo del scorecard —una corrida real, paso a paso— en demo.bayesadvisory.cl. El CHANGELOG.md registra los cambios por versión.

Desarrollo

El proyecto usa uv + hatchling, con layout src/.

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

Quién lo construye

bayesrisk lo construye Bayes Advisory, una consultora chilena de riesgo y analítica de datos. El motor es Apache-2.0 y no tiene edición comercial, tier de pago ni funciones reservadas: lo que hay en src/ es todo lo que hay. Está publicado para que puedas leer el código antes de hablar con nosotros.

Una librería calcula; no decide. El binning, la calibración y las métricas los corre el motor —pero a qué tasa central anclas (TTC o PIT), dónde pones el corte y qué supuestos sostienes ante Validación o ante tu regulador sigue siendo juicio de modelo, y eso no lo entrega ningún paquete de pip. Si ese es el problema, puedes proponer un caso. Cada caso se evalúa antes de aceptarse; si no hay caso, también te lo decimos, en menos de 48 horas hábiles.

Licencia

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

Metadata

Release files for bayesrisk 2.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bayesrisk 2.7.0
File Size Uploaded
bayesrisk-2.7.0.tar.gz 3.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for bayesrisk 2.7.0
File Interpreter ABI Platform
bayesrisk-2.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 5.6 MB

Release files / bayesrisk-2.7.0.tar.gz

Download URL bayesrisk-2.7.0.tar.gz
Size 3.4 MB
Tags Source
SHA-256 checksum
How to use checksums
0103d3207e253a8fc253997198d007e67e8757ea85c73ac4a0121649522e7852
BLAKE2b-256 checksum
How to use checksums
ec3246ab88d068b1dda8fbdb45db93a356277a9db250c1334816d11a8911563b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / bayesrisk-2.7.0-py3-none-any.whl

Download URL bayesrisk-2.7.0-py3-none-any.whl
Size 2.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
fb93b83a005b7904a59a780b828b7fdbfdd7e3a0ab2d4e1f853682e90e5efa93
BLAKE2b-256 checksum
How to use checksums
b393b0bec4182d2753d6db0699cfd4b887d44ec2bf9234c9c4a7c447df13045e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

2.12.0

2 release files

2.11.0

2 release files

2.10.0

2 release files

2.9.0

2 release files

2.8.0

2 release files

This release

2.7.0 This release

2 release files

2.6.0

2 release files

2.5.0

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.1

2 release files

2.0.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page