feat(browser): auto-commit con 178 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:22:23 +02:00
parent 7d100e7f3e
commit 763e06c127
178 changed files with 19917 additions and 317 deletions
@@ -0,0 +1,130 @@
"""Orquesta los modelos baratos del grupo `eda` en un solo bloque.
Compone las funciones puras de modelado del registry (PCA, KMeans, Isolation
Forest, tests de normalidad) sobre el subconjunto de columnas numericas de un
perfil de tabla y devuelve el bloque "models" canonico que consume el flag
``--models`` de ``profile_table``. No reescribe logica: delega en cada funcion
del registry. Es pura y determinista (todas las dependencias lo son).
"""
from datascience import (
isolation_forest_outliers,
kmeans_segments,
normality_tests,
pca_explained,
)
def _to_numeric_subset(columns: dict) -> dict:
"""Extrae las columnas numericas como {nombre: [float values]}.
Solo se quedan las columnas con ``type == "numeric"``. Para cada una, los
valores se convierten a float cuando es posible y los que son None o no
parseables se descartan (la lista resultante puede ser mas corta que la
original). Mantiene el orden de aparicion de las columnas.
Args:
columns: mapa {nombre_columna: {"values": list, "type": str}}.
Returns:
dict {nombre_columna: [float, ...]} solo con columnas numericas.
"""
numeric: dict[str, list] = {}
if not isinstance(columns, dict):
return numeric
for name, meta in columns.items():
if not isinstance(meta, dict):
continue
if meta.get("type") != "numeric":
continue
values = meta.get("values")
if not isinstance(values, (list, tuple)):
continue
parsed: list[float] = []
for v in values:
if v is None or isinstance(v, bool):
continue
try:
parsed.append(float(v))
except (TypeError, ValueError):
continue
numeric[name] = parsed
return numeric
def run_eda_models(
columns: dict,
run_pca: bool = True,
run_kmeans: bool = True,
run_isolation: bool = True,
run_normality: bool = True,
) -> dict:
"""Ejecuta los modelos baratos del grupo `eda` sobre las columnas numericas.
Composicion canonica para el flag ``--models`` de ``profile_table``. Toma el
mapa de columnas con el mismo shape que recibe ``association_matrix`` (cada
columna con ``values`` y ``type``), extrae el subconjunto numerico, y corre
los modelos pedidos sobre el. No reescribe ninguno: compone las funciones
puras ``pca_explained``, ``kmeans_segments``, ``isolation_forest_outliers``
y ``normality_tests`` del registry.
Los tests de normalidad se corren por columna numerica individual (basta 1
columna). PCA, KMeans e Isolation Forest son multivariantes y necesitan al
menos 2 columnas numericas; con menos, sus claves quedan en None y se
devuelve una ``note`` explicativa. No lanza excepciones.
``trend_slope`` NO se ejecuta aqui: requiere un orden temporal explicito y
queda disponible suelto en el registry.
Args:
columns: mapa {nombre_columna: {"values": list, "type": str}}, mismo
shape que recibe ``association_matrix``; listas alineadas por fila.
run_pca: si True, ejecuta PCA sobre el subconjunto numerico.
run_kmeans: si True, ejecuta KMeans con seleccion automatica de k.
run_isolation: si True, ejecuta Isolation Forest multivariante.
run_normality: si True, ejecuta tests de normalidad por columna.
Returns:
dict con:
n_numeric_cols: numero de columnas numericas detectadas.
pca: salida de pca_explained o None (si run_pca False / <2 cols).
kmeans: salida de kmeans_segments o None (si run_kmeans False / <2).
outliers: salida de isolation_forest_outliers o None.
normality: {col: salida de normality_tests} o None (si run_normality
False o no hay columnas numericas).
note: descripcion de por que faltan los multivariantes, si aplica.
Con menos de 2 columnas numericas devuelve los multivariantes en None y
una ``note``; ``normality`` sigue poblandose si run_normality True y hay
al menos 1 columna numerica.
"""
numeric = _to_numeric_subset(columns)
n_numeric_cols = len(numeric)
# normality es univariante: basta una columna numerica.
normality = None
if run_normality and n_numeric_cols >= 1:
normality = {name: normality_tests(values) for name, values in numeric.items()}
if n_numeric_cols < 2:
return {
"n_numeric_cols": n_numeric_cols,
"pca": None,
"kmeans": None,
"outliers": None,
"normality": normality,
"note": "insuficientes columnas numericas para modelos multivariantes",
}
pca = pca_explained(numeric) if run_pca else None
kmeans = kmeans_segments(numeric) if run_kmeans else None
outliers = isolation_forest_outliers(numeric) if run_isolation else None
return {
"n_numeric_cols": n_numeric_cols,
"pca": pca,
"kmeans": kmeans,
"outliers": outliers,
"normality": normality,
"note": "",
}