Test U de Mann-Whitney-Wilcoxon (U-test) con Python

Test U de Mann-Whitney-Wilcoxon (U-test) con Python

Joaquín Amat Rodrigo
Diciembre, 2021

Introducción


El test U de Mann-Whitney-Wilcoxon, también conocido como u-test, prueba de suma de rangos Wilcoxon o Wilcoxon rank-sum test, es un test no paramétrico que contrasta la hipótesis nula de que, dados dos valores $x$ e $y$ obtenidos aleatoriamente de dos muestras independientes, la probabilidad de que $x$ sea mayor que $y$ es igual a la probabilidad de que $y$ sea mayor que $x$. Se trata, por lo tanto, de un test para contrastar si dos muestras proceden de poblaciones equidistribuidas.

La idea sobre la que se fundamenta el u-test es la siguiente: si las dos muestras comparadas proceden de la misma población, al combinar todas las observaciones y ordenarlas de menor a mayor, cabría esperar que, las observaciones de una y otra muestra, estuviesen intercaladas aleatoriamente. Por lo contrario, si una de las muestras pertenece a una población con valores mayores o menores que la otra población, al ordenar las observaciones, estas tenderán a agruparse de modo que, las de una muestra, queden por encima de las de la otra.

Acorde a esta idea, el u-test contrasta que la probabilidad de que una observación $x$ de la población $A$ supere a una observación $y$ de la población $B$ es igual a la probabilidad de que una observación de la población $B$ supere a una de la población $A$. Es decir, que los valores de una población no tienden a ser mayores que los de la otra.

$$H_0: P(x>y)=P(y>x)$$$$H_a: P(x>y) \neq P(y>x)$$

o equivalente:

$$H_0: P(x>y)=0.5$$$$H_a: P(x>y) \neq 0.5$$

Es común encontrar mencionado que el u-test compara medianas, sin embargo, esto solo es cierto cuando las poblaciones comparadas difieren únicamente es su localización pero, el resto de características (dispersión, asimetría,...), son iguales.

El u-test se considera la versión no paramétrica del t-test de muestras independientes. Como que ocurre con muchos test no paramétricos, el u-test es menos potente que el t-test (tienen menos probabilidad de rechazar la hipótesis nula cuando realmente es falsa) ya que, al utilizar rangos, ignora valores extremos. Esto hace a su vez que el u-test sea una prueba más robusta que el t-test.

En este documento se muestra cómo utilizar las implementaciones disponibles en la librería Pingouin para realizar u-test en python.



Condiciones u-test


Las condiciones que se deben cumplir para que los resultados del u-test sean estrictamente válidos son:

  • Los datos tienen que ser independientes.

  • Los datos tienen que ser ordinales o bien se tienen que poder ordenarse de menor a mayor.

  • No es necesario asumir que las muestras se distribuyen de forma normal o que proceden de poblaciones normales. Sin embargo, para que el test compare medianas, ambas han de tener el mismo tipo de distribución (varianza, asimetría, ...).

  • Igualdad de varianza entre grupos (homocedasticidad).



Ejemplo


Supóngase que se dispone de dos muestras, de las que no se conoce el tipo de distribución de las poblaciones de origen y cuyo tamaño es demasiado pequeño para determinar si siguen una distribución normal. ¿Existe una diferencia significativa entre poblaciones?

Nota: se emplean muestras pequeñas para poder ilustrar fácilmente los pasos, no significa que con muestras tan pequeñas el u-test sea preciso.

Librerías


Las librerías utilizadas en este ejemplo son:

In [37]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
import pingouin as pg

Datos


In [38]:
# Datos
# ==============================================================================
valores_A = np.array([1.1, 3.4, 4.3, 2.1, 7.0 , 2.5])
valores_B = np.array([7.0, 8.0, 3.0, 5.0, 6.2 , 4.4])
muestra = np.repeat(['A', 'B'], repeats=6)
datos = pd.DataFrame({
            'valor': np.concatenate([valores_A, valores_B]),
            'muestra': muestra
})
datos
Out[38]:
valor muestra
0 1.1 A
1 3.4 A
2 4.3 A
3 2.1 A
4 7.0 A
5 2.5 A
6 7.0 B
7 8.0 B
8 3.0 B
9 5.0 B
10 6.2 B
11 4.4 B

Hipótesis


  • $H_0$: la probabilidad de que una observación de la población A sea mayor que una observación de la población B es igual que la probabilidad de que una observación de la población B sea mayor que una observación de la población A.

  • $H_a$: la probabilidad de que una observación de la población A sea mayor que una observación de la población B no es igual que la probabilidad de que una observación de la población B sea mayor que una observación de la población A.

Condiciones


Para poder aplicar el u-test, se requiere que la varianza sea igual en los dos grupos. Los test más recomendados para analizar homocedasticidad en estos casos son el test de Levene o el test de Fligner-Killeen, ambos trabajan con la mediana por lo que son menos sensibles a la falta de normalidad. Si se está empleando un u-test suele ser porque los datos no se distribuyen de forma normal.

In [39]:
# Test de homocedasticidad
# ==============================================================================
pg.homoscedasticity(data=datos, dv='valor', group='muestra', method='levene')
Out[39]:
W pval equal_var
levene 0.002562 0.960625 True

No hay evidencias en contra de la igualdad de varianzas.

U-Test


Una vez comprobadas las condiciones necesarias para que el u-test sea válido, se procede a calcular su estadístico, p-value asociado y tamaño de efecto. Para ello, se utiliza la función mwu de la librería pingouin.

In [40]:
# U-test (p-value y tamaño de efecto)
# ==============================================================================
pg.mwu(x=valores_A, y=valores_B, alternative='two-sided')
Out[40]:
U-val alternative p-val RBC CLES
MWU 6.5 two-sided 0.077648 0.638889 0.180556

Conclusión


El u-test no muestra evidencias notables (p-value = 0.06926) para rechazar la hipótesis nula de que, las observaciones de una muestra, tienen mayor probabilidad de tener valores superiores a las de la otra muestra.

Comparación entre t-test y u-test


Una de las aplicaciones más frecuentes del u-test es su uso como alternativa al t-test cuando las muestras no proceden de poblaciones con distribución normal o porque tienen un tamaño demasiado reducido para poder afirmarlo. Es importante tener en cuenta que, aunque ambos test permiten realizar inferencia sobre la diferencia entre poblaciones, las hipótesis contrastadas no son las mismas. Mientras que el t-test siempre compara las medias de los grupos, el u-test es menos específico. Si las distribuciones de las poblaciones subyacentes se diferencian únicamente en localización, entonces, el u-test compara medianas, para el resto de escenarios (poblaciones con distinta distribución, dispersión, asimetría...) contrasta si $P(X>Y) = P(Y>X)$. En este segundo caso, la interpretación de los p-values no es tan directa. Es debido a esta naturaleza flexible por lo que hay que ser cauteloso con el u-test. Por ejemplo, si las dos muestras comparadas proceden de poblaciones con asimetrías en direcciones opuestas, a pesar de que tanto la media como la mediana sean exactamente las mismas en ambos grupos, el p-value obtenido puede ser muy bajo.

En la práctica, el escenario en el que la única diferencia entre poblaciones es la localización es poco realista. Si las distribuciones tienen colas (asimetría) y las medias o medianas son distintas, es muy probable que las varianzas también lo sean. De hecho, la distribución normal es la única distribución estándar en la que la media y la varianza son independientes. Por lo tanto, si el u-test se está aplicando por falta de normalidad y las medias-medianas no son iguales, lo más seguro es que no se cumpla con total rigurosidad la igualdad de varianzas. Es necesario evaluar estas características para poder determinar si el u-test es suficientemente robusto para el estudio en cuestión.

Cuando la hipótesis que se quiere contrastar tiene que ser exclusivamente la igualdad de medianas se puede recurrir a la regresión de cuantiles, en concreto al cuantil 0.5, o a los test de permutaciones o bootstrapping.

U-test aplicado a muestras con asimetría opuesta


Supóngase que se dispone de las siguientes muestras y de que se desea conocer si existe diferencia significativa entre las poblaciones de origen.

In [41]:
# Datos
# ==============================================================================
grupo_a = np.array([5, 5, 5, 5, 5, 5, 7, 8, 9, 10])
grupo_b = np.array([1, 2, 3 ,4, 5, 5, 5, 5, 5, 5])

fig, axs = plt.subplots(1, 2, figsize=(7, 3))
sns.histplot(grupo_a, color="blue", ax=axs[0])
axs[0].set_title('Grupo a')
sns.histplot(grupo_b, color="green", ax=axs[1])
axs[1].set_title('Grupo b');

En vista de que el tamaño muestral es pequeño y de que ambos grupos muestran una clara asimetría, el t-test queda descartado. Una posible alternativa es emplear el u-test con la intención de comparar las medianas.

In [42]:
# U-test
# ==============================================================================
pg.mwu(x=grupo_a, y=grupo_b, alternative='two-sided')
Out[42]:
U-val alternative p-val RBC CLES
MWU 82.0 two-sided 0.007196 -0.64 0.82

El p-value obtenido indica claras evidencias en contra de la hipótesis nula de que las medianas de ambos grupos son iguales. Sin embargo, si se calculan las medianas de las muestras, el resultado es el mismo.

In [43]:
print('Mediana grupo a: ', np.median(grupo_a))
print('Mediana grupo b: ', np.median(grupo_b))
Mediana grupo a:  5.0
Mediana grupo b:  5.0

¿Cómo es posible que, siendo las medianas exactamente las mismas, el p-value obtenido en el test sea significativo? En este caso, el problema no se encuentra en el test de Mann–Whitney–Wilcoxon en sí mismo, sino en la aplicación que se le quiere dar. Como las dos poblaciones tienen asimetrías en direcciones opuestas, es decir, sus diferencias van más allá de la localización, el u-test no puede emplearse para comparar medianas. Lo que nos está indicando es que existen evidencias suficientes para afirmar que los miembros de un grupo tienen mayor probabilidad de estar por encima de los del otro.

Potencial problema del u-test con tamaños muestrales grandes


Suele recomendarse emplear el u-test en lugar del t-test cuando los tamaños muestrales son pequeños y no se tiene evidencias de que las poblaciones de origen siguen una distribución normal. Si bien esta práctica está bastante fundamentada, no hay que confundirla con la de utilizar el u-test como alternativa al t-test siempre que no se cumpla la normalidad y sin tener en cuenta el tamaño muestral.

A medida que el número de observaciones aumenta, también lo hace la robustez del t-test frente a desviaciones de la normalidad. Por otro lado, el u-test incrementa su sensibilidad a diferencias más allá de las medianas. Por ejemplo, aumenta el poder estadístico de detectar diferencias significativas en la probabilidad de que observaciones de un grupo superen a las del otro debido únicamente a diferencias en la dispersión de las poblaciones de origen y no porque sus medianas sean distintas.

Si el objetivo del estudio es identificar cualquier diferencia distribucional, esto no supone un problema pero, si lo que se quiere comparar son las medianas, se obtendrán p-values que no se corresponden con la pregunta que el investigador quiere responder.

Considérense dos muestras que proceden de dos poblaciones distintas, una con distribución normal y otra con distribución log-normal (asimetría derecha). Ambas poblaciones tienen la misma mediana pero claramente siguen distribuciones distintas.

  • Distribución normal: media = mediana

  • Distribución log-normal: media = $exp(\mu + \frac{\sigma^2}{2})$ , mediana = $exp(\mu)$

In [44]:
# Función de densidad de la distribución normal
x = np.linspace(-2, 5, num=1000)
dist_norm = stats.norm(loc=1.648721, scale=1)
y = dist_norm.pdf(x)
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(x, y, linewidth=2, label='normal')


# Función de densidad de la distribución log_normal
dist_lognorm = stats.lognorm(s=1.7, scale=np.exp(0.5))
y = dist_lognorm.pdf(x)
ax.plot(x, y, linewidth=2, label='lognormal')

ax.set_title('Distribuciones lognormal y normal con misma mediana')
ax.legend();

Supóngase ahora que el investigador, que desconoce la distribución real de las poblaciones, obtiene dos muestras de 20 observaciones cada una.

In [45]:
np.random.seed(123)
muestra_a = dist_norm.rvs(size=20)
muestra_b = dist_lognorm.rvs(size=20)

fig, axs = plt.subplots(1, 2, figsize=(7, 3))
sns.histplot(muestra_a, color="blue", ax=axs[0])
axs[0].set_title('Grupo a')
sns.histplot(muestra_b, color="green", ax=axs[1])
axs[1].set_title('Grupo b');

Dada la falta de normalidad, el investigador considera que el t-test no es adecuado para comparar la localización de las poblaciones y decide que quiere comparar medianas con el u-test.

In [46]:
pg.mwu(x=muestra_a, y=muestra_b, alternative='two-sided')
Out[46]:
U-val alternative p-val RBC CLES
MWU 212.0 two-sided 0.755743 -0.06 0.53

El resultado indica que no hay evidencias para considerar que la localización de las poblaciones es distinta y concluye que las medianas de ambas poblaciones son iguales.

Véase lo que ocurre si el tamaño muestral se incrementa de 20 a 1000 observaciones.

In [47]:
np.random.seed(123)
muestra_a = dist_norm.rvs(size=1000)
muestra_b = dist_lognorm.rvs(size=1000)

pg.mwu(x=muestra_a, y=muestra_b, alternative='two-sided')
Out[47]:
U-val alternative p-val RBC CLES
MWU 434862.0 two-sided 4.552605e-07 0.130276 0.434862

En este caso, la conclusión obtenida es totalmente opuesta, hay muchas evidencias en contra de la hipótesis nula de que ambas poblaciones tienen la misma localización por lo que el investigador podría concluir erróneamente que las medianas de ambas poblaciones son distintas.

Este ejemplo pone de manifiesto la importancia que tiene el tamaño muestral en la potencia del u-test y la necesidad de entender que, si las distribuciones no son iguales a excepción de su localización, el test es muy sensible detectando diferencias en las distribuciones a pesar de que sus medianas sean las mismas. En este caso, el investigador solo podría concluir que hay evidencias de que la distribución de las dos poblaciones se diferencia en algún aspecto, pero no podría concretar cuál.

Información de sesión

In [48]:
import session_info
session_info.show(html=False)
-----
ipykernel           6.2.0
matplotlib          3.4.3
numpy               1.19.5
pandas              1.2.5
pingouin            0.5.0
scipy               1.7.1
seaborn             0.11.0
session_info        1.0.0
-----
IPython             7.26.0
jupyter_client      6.1.7
jupyter_core        4.6.3
jupyterlab          2.1.3
notebook            6.4.0
-----
Python 3.7.9 (default, Aug 31 2020, 12:42:55) [GCC 7.3.0]
Linux-5.11.0-43-generic-x86_64-with-debian-bullseye-sid
-----
Session information updated at 2021-12-29 16:12

Bibliografía


t-tests, non-parametric tests, and large studies—a paradox of statistical practice?, Morten W Fagerland

The Wilcoxon-Mann-Whitney test under scrutiny, Fagerland MW, Sandvik L.

Performance of five two-sample location tests for skewed distributions with unequal variances, Fagerland MW, Sandvik L.

Should we always choose a nonparametric test when comparing two apparently nonnormal distributions?, Skovlund E, Fenstad GU.

Wilcoxon-Mann-Whitney or t-test? On assumptions for hypothesis tests and multiple interpretations of decision rules, Michael P.Fay and Michael A.Proschan

What hypotheses do “nonparametric” two-group tests actually test?, Conroy, Ronán M.

¿Cómo citar este documento?

Test U de Mann-Whitney-Wilcoxon (U-test) con Python por Joaquín Amat Rodrigo, disponible con licencia CC BY-NC-SA 4.0 en https://www.cienciadedatos.net/documentos/pystats10-t-test-python.html DOI


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

Mantener un sitio web tiene unos costes elevados, tu contribución me ayudará a seguir generando contenido divulgativo gratuito. ¡Muchísimas gracias! 😊


Creative Commons Licence
Este contenido, creado por Joaquín Amat Rodrigo, tiene licencia Attribution-NonCommercial-ShareAlike 4.0 International.