Spaces:
Sleeping
Sleeping
| """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) | |