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:
grupo: Control, TratA, TratB.edad: años.sexo: Hombre, Mujer.nivel_biomarcador: concentración de un biomarcador
inflamatorio (distribución no normal).respuesta_clinica: No responde, Responde.Aplicaremos tres pruebas no paramétricas clásicas:
Las pruebas se basan en el uso de rangos en lugar de asumir normalidad en las variables continuas.
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
## 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 …
## 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 ...
## [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:
read.csv("archivo.csv"): lee el archivo CSV.stringsAsFactors = TRUE: convierte cadenas de texto a
factores.factor(x, levels = ...): define el orden explícito de
los niveles del factor.summary(objeto): resumen estadístico (mínimos,
cuartiles, etc.).Normalidad por grupo
Normalidad -> control, TratA y TratB
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
##
## Control TratA TratB
## 60 60 60
Sintaxis clave:
boxplot(y ~ x, data = ...): genera boxplots comparando
y según categorías de x.tapply(variable, indice, FUN): aplica una función
FUN (ej. mean, median) por
niveles del índice (p. ej., grupo).table(x): tabla de frecuencias.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}\):
\[ 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).
Primero generamos un subconjunto de datos con solo los dos grupos a comparar:
##
## 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:
p-value).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\).
\[ 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.
Aplicamos kruskal.test():
##
## 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.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.
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.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:
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.
Queremos evaluar si la probabilidad de responder clínicamente depende del grupo de tratamiento.
Construimos la tabla de contingencia:
##
## No responde Responde
## Control 40 20
## TratA 26 34
## TratB 22 38
Aplicamos chisq.test():
##
## 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.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:
##
## No responde Responde
## Control 40 20
## TratA 26 34
## TratB 22 38
##
## No responde Responde
## Control 29.33333 30.66667
## TratA 29.33333 30.66667
## TratB 29.33333 30.66667
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:
datos_biomarcador_np.csv).str(datos)) y resúmenes
(summary(datos)).nivel_biomarcador por grupo con
boxplots.Mann, H. B., & Whitney, D. R. (1947). On a test of whether one of two random variables is stochastically larger than the other. Annals of Mathematical Statistics, 18(1), 50–60.
Kruskal, W. H., & Wallis, W. A. (1952). Use of ranks in one-criterion variance analysis. Journal of the American Statistical Association, 47(260), 583–621.
Pearson, K. (1900). On the criterion that a given system of deviations from the probable in the case of a correlated system of variables is such that it can reasonably be supposed to have arisen from random sampling. Philosophical Magazine, Series 5, 50(302), 157–175.
Siegel, S. (1956). Nonparametric Statistics for the Behavioral Sciences. McGraw–Hill.
Lehmann, E. L. (1975). Nonparametrics: Statistical Methods Based on Ranks. Holden–Day.