Más sobre ciencia de datos y estadística en: cienciadedatos.net

Introducción

El supuesto de homogeneidad de varianzas establece que la variabilidad de la variable de interés es constante entre los distintos niveles de un factor, es decir, entre diferentes grupos. Este supuesto está estrechamente relacionado con el de homocedasticidad, que en el contexto de los modelos de regresión lineal hace referencia a que la varianza de los errores (residuos) del modelo es constante a lo largo de todas las predicciones. Cuando esta condición no se cumple, se habla de heterocedasticidad.

Existen diversas pruebas estadísticas que permiten evaluar si las observaciones proceden de poblaciones con igual varianza. En todas ellas, la hipótesis nula plantea que las varianzas son iguales entre los grupos, mientras que la hipótesis alternativa sostiene que al menos una de ellas difiere. Las pruebas se diferencian principalmente en el estadístico y en la medida de centralidad utilizada para calcular las desviaciones:

  • Las pruebas basadas en la media (como la prueba de Bartlett o la versión original de Levene) presentan mayor poder estadístico cuando los datos siguen distribuciones normales.

  • Las pruebas basadas en la mediana o en métodos no paramétricos (como la versión de Levene de Brown-Forsythe o la prueba de Fligner-Killeen) son más robustas frente a desviaciones de la normalidad y distribuciones asimétricas.

En general, cuando no se puede asumir con suficiente certeza que las poblaciones siguen una distribución normal, se recomienda utilizar pruebas robustas que no dependan de este supuesto.

A lo largo de este documento se muestra cómo realizar análisis gráficos y cómo aplicar las pruebas de Levene, Bartlett y Fligner-Killeen utilizando Python.

Librerías

Las librerías utilizadas en este documento son:

# Tratamiento de datos
# ==============================================================================
import pandas as pd
import numpy as np

# Gráficos
# ==============================================================================
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('fivethirtyeight')
plt.rcParams['lines.linewidth'] = 1.5
plt.rcParams['font.size'] = 8

# Preprocesado y análisis
# ==============================================================================
from scipy import stats

# Configuración warnings
# ==============================================================================
import warnings
warnings.filterwarnings('once')

Datos

Los datos utilizados en este ejemplo se han obtenido del libro Statistical Rethinking by Richard McElreath. El set de datos contiene información recogida por Nancy Howell a finales de la década de 1960 sobre el pueblo !Kung San, que viven en el desierto de Kalahari entre Botsuana, Namibia y Angola. El objetivo es identificar si existe diferencia entre la varianza del peso de hombres y mujeres.

# Datos
# ==============================================================================
url = ('https://raw.githubusercontent.com/JoaquinAmatRodrigo/' +
       'Estadistica-machine-learning-python/master/data/Howell1.csv')
datos = pd.read_csv(url)
print(datos.info())
datos.head(4)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 544 entries, 0 to 543
Data columns (total 4 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   height  544 non-null    float64
 1   weight  544 non-null    float64
 2   age     544 non-null    float64
 3   male    544 non-null    int64  
dtypes: float64(3), int64(1)
memory usage: 17.1 KB
None
height weight age male
0 151.765 47.825606 63.0 1
1 139.700 36.485807 63.0 0
2 136.525 31.864838 65.0 0
3 156.845 53.041914 41.0 1

De todos los datos disponibles se seleccionan únicamente personas con más de 15 años.

# Separación de datos por grupo
# ==============================================================================
datos['male'] = datos['male'].astype(str)
datos = datos[(datos.age > 15)]
peso_hombres = datos.loc[datos.male == '1', 'weight']
peso_mujeres = datos.loc[datos.male == '0', 'weight']

Métodos gráficos

Dos de los métodos gráficos más empleados para el análisis homocedasticidad consiste en representar los datos mediante un boxplot o un violinplot. Con ambos gráficos el objetivo es comparar la dispersión de los grupos.

# Grafico violinplot
# ==============================================================================
fig, ax = plt.subplots(figsize=(6, 3.5))
sns.violinplot(
    x     = 'weight',
    y     = 'male',
    data  = datos,
    hue   = 'male',
    inner = 'stick',
    ax    = ax
)
ax.set_title('Distribución de peso por sexo')
ax.set_xlabel('peso')
ax.set_ylabel('sexo(1=hombre 0=mujer)');
# Grafico boxplot
# ==============================================================================
fig, ax = plt.subplots(figsize=(6, 3.5))
sns.boxplot(
    x    = 'weight',
    y    = 'male',
    data = datos,
    hue  = 'male',
    ax   = ax
)
ax.set_title('Distribución de peso por sexo')
ax.set_xlabel('peso')
ax.set_ylabel('sexo(1=hombre 0=mujer)');

Tests estadísticos

El test de Levene, el test de Bartlett y el test de Fligner-Killeen son tres de los test de hipótesis más empleados para comparar la varianza entre grupos. En todos ellos, la hipótesis nula establece que los datos proceden de distribuciones con la misma varianza (homocedasticidad). Por lo tanto, si el p-value es menor que un determinado umbral (típicamente 0.05), se considera que existen evidencias suficientes para rechazar la homocedasticidad en favor de la heterocedasticidad.

El test de Levene y el test de Fligner-Killeen (este último no paramétrico) son más robustos que el test de Bartlett frente a desviaciones de la normalidad, por lo que suele aconsejarse su uso cuando no puede asumirse normalidad. En el caso del test de Levene, es posible elegir el estadístico de centralidad utilizado para calcular las desviaciones dentro de cada grupo (media, mediana o media truncada), lo cual influye en su robustez frente a valores atípicos y distribuciones asimétricas.

El test de Bartlett, en cambio, se basa directamente en las varianzas muestrales y asume normalidad, por lo que resulta muy sensible a desviaciones de este supuesto.

Si se tiene una alta confianza en que las muestras proceden de poblaciones normalmente distribuidas, es recomendable utilizar el test de Bartlett, ya que es más potente bajo normalidad. En ausencia de esta garantía, se recomienda el test de Levene utilizando la mediana o el test no paramétrico de Fligner-Killeen, que presenta una elevada robustez frente a la no normalidad y a la presencia de valores extremos.

En la práctica aplicada, el test de Levene con la mediana suele considerarse una opción equilibrada entre robustez y potencia.

Los tres test están disponibles en la librería scipy.stats (scipy.stats.levene, scipy.stats.bartlett, scipy.stats.fligner) y en la librería pingouin (pingouin.homoscedasticity).

# Levene test
# ==============================================================================
levene_test = stats.levene(peso_hombres, peso_mujeres, center='median')
levene_test
LeveneResult(statistic=np.float64(0.18630521976263306), pvalue=np.float64(0.6662611053126026))
# Bartlett test
# ==============================================================================
bartlett_test = stats.bartlett(peso_hombres, peso_mujeres)
bartlett_test
BartlettResult(statistic=np.float64(0.8473322751459793), pvalue=np.float64(0.3573081212488608))
# Fligner test
# ==============================================================================
fligner_test = stats.fligner(peso_hombres, peso_mujeres, center='median')
fligner_test
FlignerResult(statistic=np.float64(0.1376531343594324), pvalue=np.float64(0.7106253515287645))

Ninguno de los test muestra evidencias para rechazar la hipótesis de que los dos grupos tienen la misma varianza, homocedasticidad. p-value >>>> 0.05

Bootstrapping y test de permutación

Cuando las muestras son pequeñas o no se cumplen los supuestos de los tests clásicos, se pueden emplear métodos de remuestreo como el bootstrapping o el test de permutación para evaluar la homocedasticidad. Estos métodos no dependen de supuestos específicos sobre la distribución de los datos y pueden proporcionar estimaciones más robustas de la variabilidad entre grupos.

✏️ Note

Para conocer más sobre estos métodos, consulte los documentos:

# Bootstrapping de la diferencia de varianzas
# ==============================================================================
def diff_var(x, y):
    return np.var(x, ddof=1) - np.var(y, ddof=1)

res_boot = stats.bootstrap(
    data             = (peso_hombres, peso_mujeres),
    statistic        = diff_var,
    confidence_level = 0.95,
    n_resamples      = 10_000,
    method           = "bca",
    random_state     = 34895
)

print("Intervalo de confianza del 95% para la diferencia de varianzas:")
print(res_boot.confidence_interval)
Intervalo de confianza del 95% para la diferencia de varianzas:
ConfidenceInterval(low=np.float64(-5.394767888622391), high=np.float64(16.212163831783855))

Dado que el intervalo de confianza del 95% para la diferencia de varianzas incluye el valor 0, no se encuentran evidencias suficientes para rechazar la hipótesis nula de homocedasticidad entre los dos grupos.

# Test de permutación de la diferencia de varianzas
# ==============================================================================
def var_ratio(x, y):
    return np.var(x, ddof=1) / np.var(y, ddof=1)

perm_test = stats.permutation_test(
    data             = (peso_hombres, peso_mujeres),
    statistic        = var_ratio,
    permutation_type = 'independent',
    alternative      = 'two-sided',
    n_resamples      = 10_000,
    random_state     = 34895
)
print(f"p-valor para la diferencia de varianzas: {perm_test.pvalue}")
p-valor para la diferencia de varianzas: 0.32636736326367366

El p-valor obtenido mediante el test de permutación es consistente con los resultados de los tests clásicos, indicando que no hay evidencia suficiente para rechazar la hipótesis nula de homocedasticidad entre los grupos.

Información de sesión

import session_info
session_info.show(html=False)
-----
matplotlib          3.10.8
numpy               2.2.6
pandas              2.3.3
scipy               1.15.3
seaborn             0.13.2
session_info        v1.0.1
-----
IPython             9.8.0
jupyter_client      8.7.0
jupyter_core        5.9.1
-----
Python 3.13.11 | packaged by Anaconda, Inc. | (main, Dec 10 2025, 21:28:48) [GCC 14.3.0]
Linux-6.14.0-37-generic-x86_64-with-glibc2.39
-----
Session information updated at 2026-01-20 22:17

Bibliografía

OpenIntro Statistics: Fourth Edition by David Diez, Mine Çetinkaya-Rundel, Christopher Barr

Handbook of Biological Statistics by John H. McDonald

Levene, H. (1960). In Contributions to Probability and Statistics: Essays in Honor of Harold Hotelling, I. Olkin et al. eds., Stanford University Press, pp. 278-292.

Conover, W. J., Johnson, M. E. and Johnson M. M. (1981). A comparative study of tests for homogeneity of variances, with applications to the outer continental shelf biding data. Technometrics, 23(4), 351-361.

Fligner, M.A. and Killeen, T.J. (1976). Distribution-free two-sample tests for scale. ‘Journal of the American Statistical Association.’ 71(353), 210-213.

https://www.itl.nist.gov/div898/handbook/eda/section3/eda357.htm

Instrucciones para citar

¿Cómo citar este documento?

Si utilizas este documento o alguna parte de él, te agradecemos que lo cites. ¡Muchas gracias!

Análisis de homocedasticidad y heterocedasticidad con python por Joaquín Amat Rodrigo, disponible bajo una licencia Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0 DEED) en https://www.cienciadedatos.net/documentos/pystats07-test-homocedasticidad-heterocedasticidad-python.html

¿Te ha gustado el artículo? Tu ayuda es importante

Tu contribución me ayudará a seguir generando contenido divulgativo gratuito. ¡Muchísimas gracias! 😊

Become a GitHub Sponsor

Creative Commons Licence

Este documento creado por Joaquín Amat Rodrigo tiene licencia Attribution-NonCommercial-ShareAlike 4.0 International.

Se permite:

  • Compartir: copiar y redistribuir el material en cualquier medio o formato.

  • Adaptar: remezclar, transformar y crear a partir del material.

Bajo los siguientes términos:

  • Atribución: Debes otorgar el crédito adecuado, proporcionar un enlace a la licencia e indicar si se realizaron cambios. Puedes hacerlo de cualquier manera razonable, pero no de una forma que sugiera que el licenciante te respalda o respalda tu uso.

  • No-Comercial: No puedes utilizar el material para fines comerciales.

  • Compartir-Igual: Si remezclas, transformas o creas a partir del material, debes distribuir tus contribuciones bajo la misma licencia que el original.