---
id: normality_tests_py_datascience
name: normality_tests
kind: function
lang: py
domain: datascience
version: "1.0.0"
purity: pure
signature: "def normality_tests(values: list, alpha: float = 0.05) -> dict"
description: "Tests de normalidad (Jarque-Bera, D'Agostino-Pearson, Shapiro-Wilk) sobre una columna numerica para decidir si sigue una distribucion normal. Descarta None/NaN/no-numericos y reporta consenso de los tests aplicables."
tags: [eda, models, statistics, normality, hypothesis-test, distribution, shapiro, jarque-bera]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [math, scipy]
example: |
  from normality_tests import normality_tests
  import numpy as np
  result = normality_tests(np.random.default_rng(0).normal(0, 1, 1000).tolist())
  # result["is_normal"] == True
tested: true
tests:
  - "test_normal_large_sample_is_normal"
  - "test_skewed_sample_is_not_normal"
  - "test_small_sample_returns_note"
  - "test_drops_none_nan_and_non_numeric"
  - "test_shapiro_skipped_above_5000"
  - "test_normal_below_eight_after_cleaning_is_note"
test_file_path: "python/functions/datascience/normality_tests_test.py"
file_path: "python/functions/datascience/normality_tests.py"
params:
  - name: values
    desc: "Lista de valores numericos (una columna). None, NaN, infinitos y no-numericos se descartan antes de testear. Los booleanos se excluyen."
  - name: alpha
    desc: "Nivel de significancia por test (default 0.05). normal = p > alpha (no se rechaza H0 de normalidad)."
output: >
  dict. Si n < 8 (tras limpiar): {n, note: "muestra insuficiente", is_normal: None}.
  En otro caso: {n, jarque_bera:{stat,p,normal}, dagostino:{stat,p,normal},
  shapiro:{stat,p,normal}|None (solo 3<=n<=5000), is_normal:bool}. En cada test
  normal = p > alpha. is_normal es el consenso (todos los tests aplicables coinciden
  en que los datos son normales).
---

## Ejemplo

```python
from normality_tests import normality_tests
import numpy as np

# Muestra normal -> is_normal True
normal = np.random.default_rng(0).normal(loc=10, scale=2, size=1000).tolist()
r = normality_tests(normal)
r["is_normal"]                  # True
r["jarque_bera"]["normal"]      # True
r["shapiro"]["p"] > 0.05        # True

# Muestra exponencial (sesgada) -> is_normal False
expo = np.random.default_rng(7).exponential(scale=1.0, size=1000).tolist()
normality_tests(expo)["is_normal"]   # False

# Muestra insuficiente
normality_tests([1, 2, 3, 4, 5])
# {"n": 5, "note": "muestra insuficiente", "is_normal": None}
```

## Cuando usarla

Antes de aplicar un test parametrico o un estimador que asume normalidad
(t-test, ANOVA, regresion OLS con intervalos de confianza, z-score para
outliers): comprueba primero si la columna es realmente normal. Tambien en la
fase EDA para decidir entre media (datos normales) y mediana/transformacion log
(datos sesgados), y como gate barato antes de elegir un modelo que asuma
errores gaussianos.

## Gotchas

- Funcion pura y determinista para una entrada dada, pero los p-valores
  dependen del tamano de muestra: con n muy grande casi cualquier desviacion
  minuscula de la normalidad rechaza H0 (poder estadistico alto). Interpreta
  `is_normal` junto al tamano `n` y al contexto, no como verdad absoluta.
- Shapiro-Wilk solo se ejecuta para `3 <= n <= 5000`; fuera de ese rango su
  clave es `None` y `is_normal` se decide solo con Jarque-Bera y D'Agostino.
- Con `n < 8` no se ejecuta ningun test: devuelve `note` e `is_normal: None`.
  Cuenta el `n` tras limpiar (None/NaN/no-numericos descartados), no la longitud
  bruta de la lista.
- D'Agostino-Pearson (`normaltest`) requiere internamente `n >= 8` para skew y
  kurtosis; por eso el umbral de muestra insuficiente es 8.
