"""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)