---
name: exploratory_caveats
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: pure
signature: "def exploratory_caveats(profile: dict) -> dict"
description: "Genera las advertencias que recuerdan que un EDA es EXPLORATORIO (genera hipotesis), no confirmatorio. Inspecciona un TableProfile del grupo eda y devuelve solo los caveats que aplican a lo calculado: correlacion!=causalidad, overfitting in-sample, p-values no son confirmacion, comparaciones multiples, outliers!=errores, muestra pequena, datos faltantes. El caveat general va siempre. Pura."
tags: [eda, exploratory, caveats, hypotheses, overfitting, correlation-causation, p-values, tukey, lopez-de-prado, python]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: profile
    desc: "TableProfile dict del grupo eda. Se leen defensivamente `correlations` (pares), `models` (pca/kmeans/outliers/normality), `columns` (sub-bloques `numeric` con n_outliers/outlier_pct y `trend` con p_value), `n_rows`, `null_cell_pct` y `all_null_cols`. Cualquier clave puede faltar."
output: "dict con `n` (numero de caveats), `caveats` (lista de {id, topic, message, reference} empezando por el general `exploratory_nature`) y `note` (vacio en caso normal; mensaje si el perfil esta vacio y solo se devuelve el caveat general). Nunca lanza excepcion."
tested: true
tests: ["test_perfil_vacio_solo_caveat_general", "test_none_no_lanza_y_da_general", "test_caveat_general_siempre_primero", "test_correlaciones_disparan_causalidad_y_overfitting", "test_dos_o_mas_pares_disparan_comparaciones_multiples", "test_modelos_disparan_overfitting_y_pvalues", "test_outliers_por_columna_disparan_caveat", "test_outliers_multivariantes_disparan_caveat", "test_trend_pvalue_dispara_caveat_pvalues", "test_muestra_pequena_dispara_caveat", "test_muestra_grande_no_dispara_small_sample", "test_muchos_faltantes_disparan_missing_data", "test_columnas_all_null_disparan_missing_data", "test_pocos_faltantes_no_disparan_missing_data", "test_estructura_de_cada_caveat"]
test_file_path: "python/functions/datascience/exploratory_caveats_test.py"
file_path: "python/functions/datascience/exploratory_caveats.py"
---

## Ejemplo

```python
from datascience import exploratory_caveats

profile = {
    "n_rows": 5000,
    "correlations": {"pairs": [
        {"a": "precio", "b": "ventas", "value": 0.82},
        {"a": "precio", "b": "margen", "value": -0.61},
    ]},
    "models": {"pca": {"explained": [0.6, 0.3]}, "normality": {"precio": {"is_normal": False}}},
    "columns": [{"name": "precio", "numeric": {"n_outliers": 4, "outlier_pct": 0.8}}],
}
out = exploratory_caveats(profile)
out["n"]                                    # -> 6
[c["id"] for c in out["caveats"]]
# -> ['exploratory_nature', 'correlation_not_causation', 'in_sample_overfitting',
#     'p_values_not_confirmation', 'multiple_comparisons', 'outliers_not_errors']

# Perfil vacio -> solo la advertencia general.
exploratory_caveats({})["caveats"][0]["id"]   # -> "exploratory_nature"
```

## Cuando usarla

Al cerrar un EDA, antes de entregar el reporte o de tomar decisiones sobre lo que
muestra. Convierte la disciplina exploratoria (Tukey: el EDA da hipotesis, no
conclusiones) en una lista accionable de advertencias adaptada a lo que realmente se
calculo en ese perfil. Pensada para inyectar una seccion "Advertencias / esto es
exploratorio" en el markdown de un reporte EDA, o para que un agente recuerde no
tratar una correlacion o una "significancia" como confirmacion. NO la uses para
calcular estadisticos: solo razona sobre el contenido de un TableProfile ya hecho.

## Gotchas

- Es **pura**: no recalcula nada, solo decide que advertencias aplican a partir de
  las claves presentes en el `profile`. Si una fase del EDA no se corrio (p.ej. sin
  `models`), su caveat no aparece — es deliberado.
- El caveat `exploratory_nature` (general) va SIEMPRE, incluso con perfil vacio o
  `None` (en ese caso `note` lo avisa). No lanza excepcion ante entradas raras.
- `correlations` se tolera como lista de pares o como dict con `pairs`/`strongest`
  (mismo shape que consume `render_eda_markdown`). Un solo par dispara
  `correlation_not_causation` + `in_sample_overfitting`; >=2 anaden ademas
  `multiple_comparisons`.
- Umbrales: muestra pequena si `n_rows < 30`; faltantes notables si
  `null_cell_pct > 0.2` (fraccion) o si hay `all_null_cols`. Son convenciones
  prudentes, ajustables si el caller lo necesita (recomputando sobre el mismo
  profile).
- `null_cell_pct` se asume fraccion 0-1 (como en el resto del grupo eda). Si tu
  pipeline lo guarda como porcentaje 0-100, el umbral se dispara casi siempre.
