1 Objetivo de la práctica

En esta sesión analizaremos una base de datos simulada de un experimento biomédico generada previamente en Google Colab y guardada como datos_biomarcador_np.csv.

Descargala aquí: GoogleColab

La base incluye:

Aplicaremos tres pruebas no paramétricas clásicas:

  1. Wilcoxon de suma de rangos (Mann–Whitney U) para comparar dos grupos independientes.
  2. Kruskal–Wallis para comparar tres grupos independientes.
  3. Chi-cuadrada de independencia para asociación entre variables categóricas.

Las pruebas se basan en el uso de rangos en lugar de asumir normalidad en las variables continuas.


2 Carga y preparación de datos

library(readr)
library(tidyverse)
datos_biomarcador_np <- read_csv("C:/Users/fidel/OneDrive - UNIVERSIDAD AUTONOMA DE SINALOA/COSAS/datos_biomarcador_np.csv")
#View(datos_biomarcador_np)

base<-datos_biomarcador_np

datos_biomarcador_np<- base %>% mutate_if(is.numeric, round, 2)

datos_biomarcador_np
## # A tibble: 181 × 6
##       id grupo    edad sexo   nivel_biomarcador respuesta_clinica
##    <dbl> <chr>   <dbl> <chr>              <dbl> <chr>            
##  1     1 Control    54 Hombre             37.8  No responde      
##  2     2 Control    62 Hombre              8.27 No responde      
##  3     3 Control    41 Hombre              2.89 No responde      
##  4     4 Control    48 Mujer               7.76 Responde         
##  5     5 Control    54 Hombre              8.06 No responde      
##  6     6 Control    76 Hombre             13.4  No responde      
##  7     7 Control    69 Mujer              17.9  No responde      
##  8     8 Control    53 Mujer              12.0  No responde      
##  9     9 Control    63 Hombre              3.51 Responde         
## 10    10 Control    57 Mujer               8.57 Responde         
## # ℹ 171 more rows

Asegúrate de tener el archivo datos_biomarcador_np.csv en tu directorio de trabajo de R.

# Cargar datos desde CSV
datos <- read.csv("datos_biomarcador_np.csv", stringsAsFactors = TRUE)

# Estructura básica del objeto
str(datos)
## 'data.frame':    180 obs. of  6 variables:
##  $ id               : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ grupo            : Factor w/ 3 levels "Control","TratA",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ edad             : num  54.1 62.3 40.6 48.4 54 ...
##  $ sexo             : Factor w/ 2 levels "Hombre","Mujer": 1 1 1 2 1 1 2 2 1 2 ...
##  $ nivel_biomarcador: num  37.77 8.27 2.89 7.76 8.06 ...
##  $ respuesta_clinica: Factor w/ 2 levels "No responde",..: 1 1 1 2 1 1 1 1 2 2 ...

Ajustamos los factores y niveles en el orden que nos interesa para la interpretación:

datos <- datos_biomarcador_np #

datos$grupo <- factor(datos$grupo,
                      levels = c("Control", "TratA", "TratB"))

datos$respuesta_clinica <- factor(datos$respuesta_clinica,
                                  levels = c("No responde", "Responde"))

summary(datos)
##        id             grupo         edad           sexo          
##  Min.   :  1.00   Control:60   Min.   :34.00   Length:181        
##  1st Qu.: 45.75   TratA  :60   1st Qu.:47.00   Class :character  
##  Median : 90.50   TratB  :60   Median :54.00   Mode  :character  
##  Mean   : 90.50   NA's   : 1   Mean   :54.45                     
##  3rd Qu.:135.25                3rd Qu.:62.00                     
##  Max.   :180.00                Max.   :82.00                     
##  NA's   :1                     NA's   :1                         
##  nivel_biomarcador   respuesta_clinica
##  Min.   : 2.230    No responde:88     
##  1st Qu.: 6.298    Responde   :92     
##  Median : 8.480    NA's       : 1     
##  Mean   :10.264                       
##  3rd Qu.:12.307                       
##  Max.   :37.770                       
##  NA's   :1
glimpse(datos)
## Rows: 181
## Columns: 6
## $ id                <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1…
## $ grupo             <fct> Control, Control, Control, Control, Control, Control…
## $ edad              <dbl> 54, 62, 41, 48, 54, 76, 69, 53, 63, 57, 45, 47, 44, …
## $ sexo              <chr> "Hombre", "Hombre", "Hombre", "Mujer", "Hombre", "Ho…
## $ nivel_biomarcador <dbl> 37.77, 8.27, 2.89, 7.76, 8.06, 13.42, 17.90, 11.99, …
## $ respuesta_clinica <fct> No responde, No responde, No responde, Responde, No …
str(datos)
## tibble [181 × 6] (S3: tbl_df/tbl/data.frame)
##  $ id               : num [1:181] 1 2 3 4 5 6 7 8 9 10 ...
##  $ grupo            : Factor w/ 3 levels "Control","TratA",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ edad             : num [1:181] 54 62 41 48 54 76 69 53 63 57 ...
##  $ sexo             : chr [1:181] "Hombre" "Hombre" "Hombre" "Mujer" ...
##  $ nivel_biomarcador: num [1:181] 37.77 8.27 2.89 7.76 8.06 ...
##  $ respuesta_clinica: Factor w/ 2 levels "No responde",..: 1 1 1 2 1 1 1 1 2 2 ...
datos$grupo
##   [1] Control Control Control Control Control Control Control Control Control
##  [10] Control Control Control Control Control Control Control Control Control
##  [19] Control Control Control Control Control Control Control Control Control
##  [28] Control Control Control Control Control Control Control Control Control
##  [37] Control Control Control Control Control Control Control Control Control
##  [46] Control Control Control Control Control Control Control Control Control
##  [55] Control Control Control Control Control Control TratA   TratA   TratA  
##  [64] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
##  [73] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
##  [82] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
##  [91] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
## [100] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
## [109] TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA   TratA  
## [118] TratA   TratA   TratA   TratB   TratB   TratB   TratB   TratB   TratB  
## [127] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [136] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [145] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [154] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [163] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [172] TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB   TratB  
## [181] <NA>   
## Levels: Control TratA TratB

Sintaxis clave:


3 Exploración descriptiva inicial

Normalidad por grupo

Normalidad -> control, TratA y TratB

library(rstatix)

Visualizamos la distribución de nivel_biomarcador por grupo mediante un boxplot.

boxplot(nivel_biomarcador ~ grupo,
        data = datos,
        main = "Nivel del biomarcador por grupo",
        xlab = "Grupo de tratamiento",
        ylab = "Nivel del biomarcador",
        col  = c("lightgray", "lightblue", "lightgreen"))

Calculamos medidas descriptivas por grupo:

# Medias por grupo (aunque la distribución no sea normal)
tapply(datos$nivel_biomarcador, datos$grupo, mean)
##   Control     TratA     TratB 
## 10.903833 11.505333  8.382333
# Medianas por grupo (más robustas en no normalidad)
tapply(datos$nivel_biomarcador, datos$grupo, median)
## Control   TratA   TratB 
##   8.720   9.405   7.065
# Tamaños de muestra por grupo
table(datos$grupo)
## 
## Control   TratA   TratB 
##      60      60      60

Sintaxis clave:


4 Prueba de Wilcoxon (Mann–Whitney U) para dos grupos

4.1 1. Idea teórica

La prueba de Wilcoxon de suma de rangos (Mann–Whitney U) compara dos grupos independientes sin asumir normalidad. Se basa en los rangos de los datos combinados.

Dados dos grupos de tamaños \(n_1\) y \(n_2\), con observaciones \(X_1, \dots, X_{n_1}\) y \(Y_1, \dots, Y_{n_2}\):

  1. Se combinan las observaciones \(X \cup Y\).
  2. Se ordenan de menor a mayor y se asignan rangos.
  3. Se calcula la suma de rangos para un grupo (p. ej. grupo 1):

\[ R_1 = _{i=1}^{n_1} (X_i) \]

El estadístico de Mann–Whitney U para el grupo 1 es:

\[ U_1 = n_1 n_2 + - R_1 \]

Bajo la hipótesis nula de igualdad de distribuciones, \(U\) tiene distribución conocida (exacta para muestras pequeñas, aproximación normal para grandes).

4.2 2. Ejemplo: Control vs TratA

Primero generamos un subconjunto de datos con solo los dos grupos a comparar:

datos_CA <- subset(datos, grupo %in% c("Control", "TratA"))

table(datos_CA$grupo)
## 
## Control   TratA   TratB 
##      60      60       0

Ejecutamos la prueba de Wilcoxon en R con wilcox.test():

wilcox_CA <- wilcox.test(nivel_biomarcador ~ grupo,
                         data = datos_CA,
                         alternative = "two.sided",
                         exact = FALSE,      # usa aproximación normal
                         conf.int = TRUE)    # intervalo de confianza

wilcox_CA
## 
##  Wilcoxon rank sum test with continuity correction
## 
## data:  nivel_biomarcador by grupo
## W = 1644.5, p-value = 0.4159
## alternative hypothesis: true location shift is not equal to 0
## 95 percent confidence interval:
##  -2.2199321  0.9600628
## sample estimates:
## difference in location 
##             -0.5799614

Sintaxis y argumentos clave:

  • wilcox.test(formula, data = ...):
    • nivel_biomarcador ~ grupo: fórmula respuesta ~ grupo.
    • alternative = "two.sided": hipótesis bilateral (≠).
    • exact = FALSE: fuerza la aproximación normal (muestras moderadas/grandes).
    • conf.int = TRUE: calcula intervalo de confianza de la diferencia de medianas (en escala de rangos).

Para interpretación en clase:

  • Revisar el valor p (p-value).
  • Discutir si hay evidencia de que la distribución (o mediana) del biomarcador difiere entre Control y TratA.

5 Prueba de Kruskal–Wallis para tres grupos

5.1 1. Idea teórica

El test de Kruskal–Wallis es la extensión no paramétrica del ANOVA de una vía. Compara k grupos independientes utilizando los rangos.

Sea \(k\) el número de grupos, con tamaños \(n_1, \dots, n_k\) y \(N = \sum_{i=1}^k n_i\).

  1. Se combinan todas las observaciones.
  2. Se ordenan y se asignan rangos \(R_{ij}\) a la observación \(j\) del grupo \(i\).
  3. Se calcula la suma de rangos por grupo:

\[ R_i = *{j=1}^{n_i} R*{ij} \]

La estadística de Kruskal–Wallis es:

\[ H = _{i=1}^k - 3(N + 1) \]

Bajo la hipótesis nula (todas las poblaciones tienen la misma distribución/mediana), \(H\) se aproxima a una distribución \(\chi^2\) con \(k - 1\) grados de libertad.

5.2 2. Ejemplo: comparación de los tres grupos

Aplicamos kruskal.test():

kruskal_res <- kruskal.test(nivel_biomarcador ~ grupo, data = datos)
kruskal_res
## 
##  Kruskal-Wallis rank sum test
## 
## data:  nivel_biomarcador by grupo
## Kruskal-Wallis chi-squared = 11.271, df = 2, p-value = 0.003568

Sintaxis clave:

  • kruskal.test(y ~ x, data = ...): prueba Kruskal–Wallis para variable continua y y factor x.
  • Interesa:
    • kruskal_res$statistic: valor de \(H\).
    • kruskal_res$parameter: grados de libertad.
    • kruskal_res$p.value: valor p.

Si el valor p es pequeño (por ejemplo < 0.05), concluimos que al menos un grupo difiere.

5.3 3. Comparaciones post hoc (parejas de grupos)

Si el test global es significativo, podemos hacer comparaciones dos a dos con pruebas de Wilcoxon ajustando por comparaciones múltiples:

pairwise_res <- pairwise.wilcox.test(datos$nivel_biomarcador,
                                     datos$grupo,
                                     p.adjust.method = "bonferroni")

pairwise_res
## 
##  Pairwise comparisons using Wilcoxon rank sum test with continuity correction 
## 
## data:  datos$nivel_biomarcador and datos$grupo 
## 
##       Control TratA
## TratA 1.000   -    
## TratB 0.030   0.006
## 
## P value adjustment method: bonferroni

Sintaxis clave:

  • pairwise.wilcox.test(x, g, p.adjust.method = ...)
    • x: variable continua.
    • g: factor de grupos.
    • p.adjust.method = "bonferroni": corrección conservadora para múltiples comparaciones.

5.4 4. Tamaño del efecto global (\(\eta^2_H\))

Una medida sencilla del tamaño del efecto para Kruskal–Wallis es:

\[ ^2_H = \]

H <- kruskal_res$statistic
k <- length(levels(datos$grupo))
N <- nrow(datos)

eta2_H <- as.numeric((H - (k - 1)) / (N - 1))
eta2_H
## [1] 0.05150688

Interpretación aproximada:

  • \(\eta^2_H \approx 0.01\): pequeño.
  • \(\eta^2_H \approx 0.06\): medio.
  • \(\eta^2_H \geq 0.14\): grande (valores guía, no absolutos).

6 Prueba de Chi-cuadrada de independencia

6.1 1. Idea teórica

La prueba de Chi-cuadrada de independencia evalúa si dos variables categóricas están asociadas.

Sea una tabla de contingencia \(I \times J\) con frecuencias observadas \(O_{ij}\) y esperadas \(E_{ij}\) bajo la hipótesis de independencia:

\[ E_{ij} = \]

La estadística chi-cuadrada es:

\[ ^2 = *{i=1}^{I}* ^{J} \]

Bajo H0 (independencia), \(\chi^2\) se distribuye aproximadamente como chi-cuadrada con \((I-1)(J-1)\) grados de libertad.

6.2 2. Ejemplo: grupo vs respuesta clínica

Queremos evaluar si la probabilidad de responder clínicamente depende del grupo de tratamiento.

Construimos la tabla de contingencia:

tabla_resp <- table(datos$grupo, datos$respuesta_clinica)
tabla_resp
##          
##           No responde Responde
##   Control          40       20
##   TratA            26       34
##   TratB            22       38

Aplicamos chisq.test():

chi_res <- chisq.test(tabla_resp, correct = FALSE)  # sin corrección de continuidad
chi_res
## 
##  Pearson's Chi-squared test
## 
## data:  tabla_resp
## X-squared = 11.917, df = 2, p-value = 0.002584

Sintaxis clave:

  • chisq.test(x) donde x es una tabla (table) de frecuencias observadas.
  • Elementos importantes:
    • chi_res$observed: tabla de frecuencias observadas \(O_{ij}\).
    • chi_res$expected: tabla de frecuencias esperadas \(E_{ij}\).
    • chi_res$statistic: valor de \(\chi^2\).
    • chi_res$p.value: valor p.
    • chi_res$parameter: grados de libertad.

Podemos inspeccionar observadas y esperadas:

chi_res$observed
##          
##           No responde Responde
##   Control          40       20
##   TratA            26       34
##   TratB            22       38
chi_res$expected
##          
##           No responde Responde
##   Control    29.33333 30.66667
##   TratA      29.33333 30.66667
##   TratB      29.33333 30.66667

6.3 3. Tamaño del efecto: Cramér’s V

Cramér’s V es una medida de fuerza de asociación para tablas de dimensión \(I \times J\):

\[ V = \]

chi2 <- chi_res$statistic
N_chi <- sum(tabla_resp)
I <- nrow(tabla_resp)
J <- ncol(tabla_resp)

cramer_V <- as.numeric( sqrt(chi2 / (N_chi * (min(I - 1, J - 1)))) )
cramer_V
## [1] 0.2573044

Interpretación orientativa de Cramér’s V:

  • ~0.1: asociación pequeña.
  • ~0.3: asociación moderada.
  • ≥0.5: asociación fuerte (depende del contexto y tamaño muestral).

7 Guía rápida

  1. Cargar el CSV generado en Colab (datos_biomarcador_np.csv).
  2. Verificar estructura (str(datos)) y resúmenes (summary(datos)).
  3. Revisar distribución de nivel_biomarcador por grupo con boxplots.
  4. Aplicar Wilcoxon (Mann–Whitney) para dos grupos (Control vs TratA):
    • Comprobar hipótesis.
    • Interpretar valor p.
  5. Aplicar Kruskal–Wallis para los tres grupos:
    • Interpretar test global.
    • Realizar comparaciones post hoc (pairwise Wilcoxon con ajuste Bonferroni).
    • Calcular \(\eta^2_H\) como tamaño del efecto.
  6. Construir tabla grupo × respuesta_clinica y aplicar Chi-cuadrada:
    • Revisar observadas y esperadas.
    • Interpretar valor p.
    • Calcular Cramér’s V.

8 Referencias sugeridas