eda-express / eda /report.py
aitziberluis's picture
Upload 18 files
b8d091a verified
Raw
History Blame Contribute Delete
2.82 kB
"""Exportación del análisis completo a un informe Markdown descargable."""
from __future__ import annotations
from datetime import date
import pandas as pd
from . import profiler
def _table_md(df: pd.DataFrame) -> str:
if df.empty:
return "*(sin datos)*\n"
return df.to_markdown(index=False) + "\n"
def build_report(
df: pd.DataFrame,
dataset_name: str,
alerts: list[dict],
target: str | None = None,
insights: str | None = None,
) -> str:
ov = profiler.overview(df)
parts = [
f"# Informe exploratorio — {dataset_name}",
f"*Generado el {date.today().isoformat()} con EDA Express*",
"",
"## Visión general",
f"- **Filas:** {ov['filas']:,} | **Columnas:** {ov['columnas']} "
f"({ov['numericas']} numéricas, {ov['categoricas']} categóricas)",
f"- **Memoria:** {ov['memoria_mb']} MB",
f"- **Faltantes:** {ov['faltantes_total']:,} celdas ({ov['faltantes_pct']}%)",
f"- **Filas duplicadas:** {ov['filas_duplicadas']:,} ({ov['duplicadas_pct']}%)",
"",
"## Alertas de calidad",
]
if alerts:
for a in alerts:
icon = {"critico": "[CRITICO]", "aviso": "[AVISO]", "info": "[INFO]"}[a["nivel"]]
parts.append(f"- {icon} **{a['columna']}** — {a['mensaje']}. {a['recomendacion']}")
else:
parts.append("- Sin alertas: el dataset pasa todas las comprobaciones.")
parts += ["", "## Columnas", _table_md(profiler.column_table(df))]
missing = profiler.missing_table(df)
if not missing.empty:
parts += ["## Valores faltantes", _table_md(missing)]
numeric = profiler.numeric_table(df)
if not numeric.empty:
parts += ["## Variables numéricas", _table_md(numeric)]
categorical = profiler.categorical_table(df)
if not categorical.empty:
parts += ["## Variables categóricas", _table_md(categorical)]
top_corr = profiler.top_correlations(profiler.correlation_matrix(df))
if not top_corr.empty:
parts += ["## Correlaciones más fuertes", _table_md(top_corr)]
if target:
parts += [f"## Análisis respecto a '{target}'"]
if profiler.target_kind(df, target) == "categorico":
parts += ["### Balance de clases", _table_md(profiler.class_balance(df, target))]
corr_target = profiler.correlations_with_target(df, target)
if not corr_target.empty:
parts += ["### Correlación con el objetivo", _table_md(corr_target)]
if insights:
parts += ["## Conclusiones (generadas con LLM)", insights, ""]
parts += [
"---",
"*Los resultados son descriptivos: las decisiones (imputar, eliminar, "
"transformar) requieren conocer el contexto del dato.*",
]
return "\n".join(parts)