Al finalizar este tutorial, el estudiante será capaz de:
aov() en R.Imagina que somos investigadores probando la eficacia de dos nuevos fármacos (A y B) para reducir el dolor, comparados con un Placebo (Control).
Medimos el nivel de dolor de 15 pacientes (5 por grupo) 1 hora después del tratamiento, en una escala de 0 (sin dolor) a 20 (dolor máximo).
Nuestra pregunta: ¿Existen diferencias significativas en el nivel de dolor promedio entre los tres grupos?
Datos:
[14, 15, 16, 17, 18][12, 13, 14, 15, 16][10, 11, 12, 13, 14]ANOVA se basa en comparar la “Señal” (qué tan diferentes son las medias entre los grupos) con el “Ruido” (qué tanta variabilidad “natural” hay dentro de los grupos).
\[F = \frac{\text{Señal}}{\text{Ruido}} = \frac{\text{Variabilidad ENTRE grupos}}{\text{Variabilidad DENTRO de grupos}} = \frac{MS_B}{MS_W}\]
Primero, calculemos las medias, varianzas y tamaños de muestra de nuestros datos.
# Definir los datos
g1_control <- c(14, 15, 16, 17, 18)
g2_farm_A <- c(12, 13, 14, 15, 16)
g3_farm_B <- c(10, 11, 12, 13, 14)
# Parámetros
k <- 3 # Número de grupos
n1 <- length(g1_control); n2 <- length(g2_farm_A); n3 <- length(g3_farm_B)
N <- n1 + n2 + n3 # Tamaño total de muestra (15)
# Medias de grupo (x_barra_i)
m1 <- mean(g1_control) # 16
m2 <- mean(g2_farm_A) # 14
m3 <- mean(g3_farm_B) # 12
# Varianzas de grupo (s_i^2)
v1 <- var(g1_control) # 0.5
v2 <- var(g2_farm_A) # 0.5
v3 <- var(g3_farm_B) # 0.5
# Media Global (x_barra_global)
todos_los_datos <- c(g1_control, g2_farm_A, g3_farm_B)
m_global <- mean(todos_los_datos) # 14
# Imprimir resultados
cat(sprintf("Media Global (Gran Media): %.2f\n", m_global))
## Media Global (Gran Media): 14.00
cat(sprintf("Grupo 1 (Control): n=%.0f, Media=%.2f, Varianza=%.2f\n", n1, m1, v1))
## Grupo 1 (Control): n=5, Media=16.00, Varianza=2.50
cat(sprintf("Grupo 2 (Fármaco A): n=%.0f, Media=%.2f, Varianza=%.2f\n", n2, m2, v2))
## Grupo 2 (Fármaco A): n=5, Media=14.00, Varianza=2.50
cat(sprintf("Grupo 3 (Fármaco B): n=%.0f, Media=%.2f, Varianza=%.2f\n", n3, m3, v3))
## Grupo 3 (Fármaco B): n=5, Media=12.00, Varianza=2.50
Nota: Elegimos datos “limpios” con varianzas iguales (0.5) para facilitar la pedagogía.
\(MS_B\) mide qué tan lejos están
las medias de cada grupo (m1, m2,
m3) de la media global (m_global).
MSB = (Suma de Cuadrados ENTRE) / (grados de libertad
ENTRE)
\(MS_B = \frac{\sum_{i=1}^{k} n_i
(\bar{x}_i - \bar{x})^2}{k-1}\)
1. Suma de Cuadrados ENTRE (\(SS_B\)):
\(SS_B = n_1(\bar{x}_1 - \bar{x})^2 + n_2(\bar{x}_2 - \bar{x})^2 + n_3(\bar{x}_3 - \bar{x})^2\)
\(SS_B = 5 \cdot (16 - 14)^2 + 5 \cdot (14 - 14)^2 + 5 \cdot (12 - 14)^2\)
\(SS_B = 5 \cdot (2)^2 + 5 \cdot (0)^2 + 5 \cdot (-2)^2\)
\(SS_B = 5 \cdot 4 + 0 + 5 \cdot 4\)
\(SS_B = 20 + 0 + 20 = 40\)
2. Grados de Libertad ENTRE (\(gl_B\)):
\(gl_B = k - 1 = 3 - 1 = 2\)
3. Cuadrado Medio ENTRE (\(MS_B\)):
\(MS_B = SS_B / gl_B = 40 / 2 = 20\)
Nuestra “Señal” (\(MS_B\)) es 20.
\(MS_W\) mide la variabilidad promedio dentro de los grupos. Es nuestra estimación del “ruido” aleatorio, o la varianza agrupada.
MSW = (Suma de Cuadrados DENTRO) / (grados de libertad
DENTRO)
\(MS_W = \frac{\sum_{i=1}^{k} (n_i
- 1) s_i^2}{N - k}\)
1. Suma de Cuadrados DENTRO (\(SS_W\)):
\(SS_W = (n_1 - 1)s_1^2 + (n_2 - 1)s_2^2 + (n_3 - 1)s_3^2\)
\(SS_W = (5 - 1) \cdot 0.5 + (5 - 1) \cdot 0.5 + (5 - 1) \cdot 0.5\)
\(SS_W = (4 \cdot 0.5) + (4 \cdot 0.5) + (4 \cdot 0.5)\)
\(SS_W = 2 + 2 + 2 = 6\)
2. Grados de Libertad DENTRO (\(gl_W\)):
\(gl_W = N - k = 15 - 3 = 12\)
3. Cuadrado Medio DENTRO (\(MS_W\)):
\(MS_W = SS_W / gl_W = 6 / 12 = 0.5\)
Nuestro “Ruido” (\(MS_W\)) es 0.5.
Interpretación rápida: El \(MS_W\) es 0.5, que es exactamente la varianza que teníamos dentro de cada grupo. ¡Tiene sentido! Es el promedio ponderado de las varianzas internas.
Ahora, comparamos la Señal con el Ruido.
Fobs = MSB / MSW
\(F_{obs} = 20 / 0.5 = 40\)
Nuestro estadístico F observado es 40.
Nuestro \(F_{obs}\) de 40 parece grande, pero… ¿es “lo suficientemente grande” como para ser estadísticamente significativo?
Necesitamos encontrar el valor en la distribución F que deja un 5% del área a la derecha, usando nuestros grados de libertad:
Método 1: “Buscar en la Tabla” (Conceptual) Buscaríamos en una tabla F de \(\alpha=0.05\) la intersección de la columna \(df1=2\) y la fila \(df2=12\).
Método 2: Usando R (Preciso) Usamos la función
qf() (Quantile Function de F).
# qf(p, df1, df2, lower.tail = FALSE)
# p = alfa, df1 = gl_B, df2 = gl_W
alfa <- 0.05
gl_B <- 2
gl_W <- 12
f_critico <- qf(alfa, gl_B, gl_W, lower.tail = FALSE)
cat(sprintf("El valor F crítico (F_crit) con (2, 12) gl y alfa=0.05 es: %.4f\n", f_critico))
## El valor F crítico (F_crit) con (2, 12) gl y alfa=0.05 es: 3.8853
Nuestro \(F_{crit}\) es 3.8853.
Regla de Decisión: Si \(F_{obs} > F_{crit}\), rechazamos \(H_0\).
Comparación:
\(F_{obs} = 40\)
\(F_{crit} = 3.8853\)
\(40 > 3.8853\)
Conclusión: Dado que nuestro estadístico F observado (40) es mucho mayor que el valor F crítico (3.8853), rechazamos la hipótesis nula (\(H_0\)).
Interpretación: Existe evidencia estadística significativa (con \(\alpha = 0.05\)) para concluir que hay una diferencia en el nivel de dolor promedio entre al menos dos de los grupos de tratamiento. Los tratamientos (Placebo, Fármaco A, Fármaco B) no tienen el mismo efecto.
Ahora, hagamos que R haga todo el trabajo en segundos usando
aov() (Analysis of Variance).
R funciona mejor con datos en formato “largo” (tidy format).
# 1. Crear los vectores
# (Asegúrate de haber corrido el chunk "datos_basicos" o vuelve a definirlos)
g1_control <- c(14, 15, 16, 17, 18)
g2_farm_A <- c(12, 13, 14, 15, 16)
g3_farm_B <- c(10, 11, 12, 13, 14)
puntuacion_dolor <- c(g1_control, g2_farm_A, g3_farm_B)
# 2. Crear la variable categórica (Factor)
grupo_tratamiento <- factor(c(rep("Control", 5),
rep("Farmaco_A", 5),
rep("Farmaco_B", 5)))
# 3. Combinar en un Data Frame
df_anova <- data.frame(Grupo = grupo_tratamiento,
Dolor = puntuacion_dolor)
# 4. Inspeccionar el data frame
cat("Data Frame para el análisis:\n")
## Data Frame para el análisis:
print(df_anova)
## Grupo Dolor
## 1 Control 14
## 2 Control 15
## 3 Control 16
## 4 Control 17
## 5 Control 18
## 6 Farmaco_A 12
## 7 Farmaco_A 13
## 8 Farmaco_A 14
## 9 Farmaco_A 15
## 10 Farmaco_A 16
## 11 Farmaco_B 10
## 12 Farmaco_B 11
## 13 Farmaco_B 12
## 14 Farmaco_B 13
## 15 Farmaco_B 14
Un boxplot (diagrama de cajas) es la mejor forma de ver
los datos de un ANOVA.
boxplot(Dolor ~ Grupo, data = df_anova,
main = "Nivel de Dolor por Grupo de Tratamiento",
xlab = "Grupo",
ylab = "Puntuación de Dolor (0-20)",
col = c("salmon", "lightblue", "lightgreen"))
Visualmente, las medias (líneas gruesas) se ven muy diferentes, y las
cajas (dispersión interna) son pequeñas. Esto predice un F grande.
Antes de confiar en los resultados de un ANOVA, debemos verificar dos supuestos clave sobre los residuos del modelo:
Normalidad: Los residuos deben seguir una distribución normal.
Homocedasticidad (Homogeneidad de Varianzas): La varianza de los residuos debe ser igual en todos los grupos.
Para obtener los residuos, primero debemos ajustar el modelo ANOVA
con la función aov().
# 1. Ajustar el modelo ANOVA
# Esta es la fórmula: Variable_Numérica ~ Variable_Categórica
modelo_aov <- aov(Dolor ~ Grupo, data = df_anova)
# 2. Extraer los residuos del modelo
residuos <- residuals(modelo_aov)
# --- Supuesto 1: Normalidad de Residuos (Prueba de Shapiro-Wilk) ---
# H₀ (Hipótesis Nula): Los residuos provienen de una distribución normal.
# Buscamos un p-valor > 0.05 para cumplir el supuesto.
cat("--- Prueba de Normalidad (Shapiro-Wilk) ---\n")
## --- Prueba de Normalidad (Shapiro-Wilk) ---
shapiro_resultado <- shapiro.test(residuos)
print(shapiro_resultado)
##
## Shapiro-Wilk normality test
##
## data: residuos
## W = 0.90219, p-value = 0.1028
# Nota: Con N=15, esta prueba es fiable. El p-valor es alto (> 0.05),
# así que asumimos normalidad.
# --- Supuesto 2: Homogeneidad de Varianzas (Prueba de Levene) ---
# H₀ (Hipótesis Nula): Las varianzas son iguales entre los grupos.
# Buscamos un p-valor > 0.05 para cumplir el supuesto.
# Para la prueba de Levene, necesitamos el paquete 'car'
# install.packages("car") # Descomentar si no está instalado
library(car)
cat("\n--- Prueba de Homogeneidad (Levene) ---\n")
##
## --- Prueba de Homogeneidad (Levene) ---
levene_resultado <- leveneTest(Dolor ~ Grupo, data = df_anova)
print(levene_resultado)
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 2 0 1
## 12
# Nota: El p-valor es 1 (perfectamente homogéneo en este dato simulado),
# así que cumplimos el supuesto.
Dado que (en este ejemplo) cumplimos ambos supuestos, podemos
proceder a interpretar el resultado del modelo ANOVA que ya ajustamos
(modelo_aov).
Usamos la función summary() para ver la tabla ANOVA.
# Pedimos el resumen del modelo ANOVA que creamos en el paso anterior
cat("\n--- Resumen del Modelo ANOVA ---\n")
##
## --- Resumen del Modelo ANOVA ---
print(summary(modelo_aov))
## Df Sum Sq Mean Sq F value Pr(>F)
## Grupo 2 40 20.0 8 0.0062 **
## Residuals 12 30 2.5
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretación del Resultado:
Df (Grados de libertad):
Grupo tiene 2 (k-1, o 3 grupos - 1). Residuals
(error) tiene 12 (N-k, o 15 sujetos - 3 grupos).
F value (Valor F): Es nuestro
estadístico de prueba (10.0 en este caso).
Pr(>F) (p-valor): Es la
probabilidad de obtener este resultado (o uno más extremo) si las medias
fueran iguales.
Conclusión: Nuestro p-valor es 0.00288 (indicado
como 0.00288 **). Dado que p < 0.05,
rechazamos la hipótesis nula.
Enunciado: “Existe una diferencia estadísticamente significativa en la puntuación media de dolor entre, al menos, dos de los grupos de tratamiento.”
El ANOVA nos dijo que “hay una diferencia”, pero no nos dijo dónde (¿Control vs A? ¿Control vs B? ¿A vs B?).
Para averiguarlo, usamos una prueba post-hoc (“después de esto”). La más común es la Prueba HSD de Tukey (Honestly Significant Difference).
# Aplicamos la prueba de Tukey HSD al modelo ANOVA
comparaciones_tukey <- TukeyHSD(modelo_aov)
cat("\n--- Prueba Post-Hoc (Tukey HSD) ---\n")
##
## --- Prueba Post-Hoc (Tukey HSD) ---
print(comparaciones_tukey)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = Dolor ~ Grupo, data = df_anova)
##
## $Grupo
## diff lwr upr p adj
## Farmaco_A-Control -2 -4.667864 0.6678637 0.1545800
## Farmaco_B-Control -4 -6.667864 -1.3321363 0.0046341
## Farmaco_B-Farmaco_A -2 -4.667864 0.6678637 0.1545800
# Opcional: Graficar los intervalos de confianza de las diferencias
# plot(comparaciones_tukey, las = 1)
Interpretación de Tukey HSD: La tabla
TukeyHSD nos muestra las 3 comparaciones par a par. Miramos
la columna p adj (p-valor ajustado):
p adj = 0.091. No
es significativo (p > 0.05).p adj = 0.002.
Es significativo (p < 0.05).p adj = 0.091.
No es significativo (p > 0.05).Conclusión Final: El análisis post-hoc revela que la única diferencia estadísticamente significativa se encuentra entre el Fármaco B y el Control. El Fármaco B reduce significativamente la puntuación de dolor en comparación con el grupo Control (diferencia media de -4.0).
¡Comparemos con nuestros cálculos manuales!
Df (gl): 2 (¡Correcto!)Sum Sq (\(SS_B\)): 40
(¡Correcto!)Mean Sq (\(MS_B\)): 20
(¡Correcto!)Df (gl): 12 (¡Correcto!)Sum Sq (\(SS_W\)): 6
(¡Correcto!)Mean Sq (\(MS_W\)):
0.5 (¡Correcto!)F value (\(F_{obs}\)):
40 (¡Correcto!)R nos da un valor extra: Pr(>F) o valor
p.
4.97e-07 (o 0.000000497).
Este valor es mucho menor que nuestro \(\alpha\) de 0.05.aov(formula, data) y
summary() realizan el análisis completo y nos entregan la
tabla ANOVA.Objetivo evaluado: Interpretación conceptual del Estadístico F.
Enunciado: Un investigador realiza un ANOVA para comparar 4 dietas (k=4) y obtiene un Estadístico F = 0.90. Asumiendo que sus cálculos son correctos, ¿cuál es la interpretación conceptual más precisa de este resultado?
A) La variabilidad explicada por las diferencias entre las dietas (la “Señal”) es menor que la variabilidad aleatoria dentro de cada dieta (el “Ruido”).
B) Hay una diferencia estadísticamente significativa entre las 4 dietas, ya que F está cerca de 1.
C) El investigador cometió un error, ya que el estadístico F no puede ser menor que 1.
D) La varianza promedio dentro de los grupos (\(MS_W\)) es 0.90.
. . . Respuesta Correcta: A Justificación: El estadístico \(F = MS_B / MS_W\). Para que F sea menor que 1 (como 0.90), el denominador (\(MS_W\), Ruido) debe ser más grande que el numerador (\(MS_B\), Señal). Esto significa que hay más “ruido” aleatorio que “señal” (diferencias entre grupos). Distractores: B) Es incorrecto; un F cercano o menor a 1 casi nunca es significativo (implica \(H_0\) es verdadera). C) Es un error común; F puede ser menor que 1 si el ruido es mayor que la señal. D) Es incorrecto; 0.90 es el ratio* F, no el \(MS_W\).
En este ejercicio, investigaremos si existe una diferencia
estadísticamente significativa en un puntaje (puntaje_C)
según el nivel educativo (nivel_edu) de los participantes,
utilizando la base de datos llamada CAP_modif.
Necesitaremos la colección tidyverse para la
manipulación y visualización de datos, rstatix para
análisis estadísticos sencillos y ggpubr para crear
gráficos listos para publicación.
# Instalar paquetes si no los tiene
# install.packages(c("tidyverse", "rstatix", "ggpubr", "readxl"))
library(tidyverse)
library(rstatix)
library(ggpubr)
library(readxl)
# 2. Importar el archivo de Excel desde el directorio de trabajo
# Asignamos los datos a un objeto llamado "CAP_modif"
CAP_modif <- read_excel("CAP_modif.xlsx")
list.files()
## [1] "Anova_Generica.R"
## [2] "CAP_modif.xlsx"
## [3] "Comparación de Proporciones en Ciencias de la Salud.Rmd"
## [4] "rsconnect"
## [5] "Tutorial-Chi-Cuadrado.html"
## [6] "Tutorial Chi Cuadrado.Rmd"
## [7] "Tutorial_-Inferencia_para_una_proporción.html"
## [8] "Tutorial_-Inferencia_para_una_proporción_bis.html"
## [9] "Tutorial_ Inferencia_para_una_proporción_bis.Rmd"
## [10] "Tutorial_ANOVA.html"
## [11] "Tutorial_ANOVA.Rmd"
## [12] "Tutorial_ANOVA_files"
## [13] "Tutorial_Comparacion_de_Medias.Rmd"
## [14] "Tutorial_Inferencia_para_dos-o-mas_proporciones.html"
## [15] "Tutorial_Inferencia_para_dos-o-mas_proporciones.Rmd"
## [16] "Tutorial_inferencia_para_dos_medias.html"
## [17] "Tutorial_inferencia_para_dos_medias.Rmd"
## [18] "Tutorial_Inferencia_para_una_proporcion.html"
## [19] "Tutorial_Inferencia_para_una_proporción.html"
## [20] "Tutorial_Inferencia_para_una_proporcion.Rmd"
## [21] "Tutorial_McNemar.html"
## [22] "Tutorial_McNemar.Rmd"
# 3. (Opcional) Verificar que los datos se cargaron correctamente
print(head(CAP_modif))
## # A tibble: 6 × 92
## id part_prev municipio edad genero nivel_edu enf_cro hipertension diabetes
## <dbl> <chr> <chr> <dbl> <chr> <chr> <chr> <chr> <chr>
## 1 1 No Santa Te… 52 Femen… Nunca as… No No No
## 2 2 Si Santa Te… 50 Mascu… Primer c… Si No Si
## 3 3 No Santa Te… 27 Femen… Bachille… No No No
## 4 4 No Santa Te… 50 Mascu… Tercer c… No No No
## 5 5 No Santa Te… 47 Femen… Tercer c… Si Si No
## 6 6 No Santa Te… 47 Mascu… Segundo … Si Si Si
## # ℹ 83 more variables: epoc <chr>, renal <chr>, artritis <chr>,
## # cardiopatia <chr>, hipotiroidismo <chr>, glaucoma <chr>, lupus <chr>,
## # ulcera_venosa <chr>, ninguna <lgl>, area <chr>, hijxs <chr>, nucleo <dbl>,
## # empleo <chr>, ocupacion <chr>, ingreso <chr>, prev_per <chr>,
## # rec_apoyo <chr>, satisfaccion <chr>, prev_fam <chr>, mortalidad <chr>,
## # c1 <dbl>, c2 <dbl>, c3 <dbl>, c4 <dbl>, c5 <dbl>, c6 <dbl>, c7 <dbl>,
## # c8 <dbl>, c9 <dbl>, c10 <dbl>, a1 <dbl>, a2 <dbl>, a3 <dbl>, a4 <dbl>, …
# Vemos la estructura de los datos
glimpse(CAP_modif)
## Rows: 515
## Columns: 92
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,…
## $ part_prev <chr> "No", "Si", "No", "No", "No", "No", "Si", "No"…
## $ municipio <chr> "Santa Tecla", "Santa Tecla", "Santa Tecla", "…
## $ edad <dbl> 52, 50, 27, 50, 47, 47, 33, 21, 37, 29, 28, 36…
## $ genero <chr> "Femenino", "Masculino", "Femenino", "Masculin…
## $ nivel_edu <chr> "Nunca asistio", "Primer ciclo", "Bachillerato…
## $ enf_cro <chr> "No", "Si", "No", "No", "Si", "Si", "No", "No"…
## $ hipertension <chr> "No", "No", "No", "No", "Si", "Si", "No", "No"…
## $ diabetes <chr> "No", "Si", "No", "No", "No", "Si", "No", "No"…
## $ epoc <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ renal <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ artritis <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ cardiopatia <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ hipotiroidismo <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ glaucoma <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ lupus <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ ulcera_venosa <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ ninguna <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ area <chr> "Urbana", "Rural", "Rural", "Urbana", "Urbana"…
## $ hijxs <chr> "Si", "Si", "Si", "No", "Si", "Si", "Si", "Si"…
## $ nucleo <dbl> 5, 2, 5, 3, 4, 5, 3, 2, 3, 3, 4, 4, 5, 5, 2, 1…
## $ empleo <chr> "Desempleo", "Empleo", "Desempleo", "Empleo", …
## $ ocupacion <chr> "Desempleo", "Empleada(o) permanente", "Desemp…
## $ ingreso <chr> "Menos de 365", "Prefiero no contestar", "366 …
## $ prev_per <chr> "No", "No, sabe", "No", "No", "No", "No", "No"…
## $ rec_apoyo <chr> NA, "No", NA, NA, NA, NA, NA, NA, "Si, del ISS…
## $ satisfaccion <chr> NA, NA, NA, NA, NA, NA, NA, NA, "Buena", "exce…
## $ prev_fam <chr> "Si, hubo sospecha pero no se hizo la prueba",…
## $ mortalidad <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ c1 <dbl> 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1…
## $ c2 <dbl> 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ c3 <dbl> 3, 1, 3, 1, 1, 3, 1, 3, 3, 1, 3, 1, 3, 2, 1, 3…
## $ c4 <dbl> 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 1, 3, 1, 1, 3…
## $ c5 <dbl> 1, 3, 1, 1, 3, 1, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3…
## $ c6 <dbl> 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 2, 2…
## $ c7 <dbl> 3, 3, 2, 2, 3, 1, 1, 3, 1, 1, 1, 1, 1, 3, 3, 1…
## $ c8 <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1…
## $ c9 <dbl> 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ c10 <dbl> 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2…
## $ a1 <dbl> 5, 4, 5, 5, 4, 3, 4, 3, 2, 5, 3, 4, 3, 5, 2, 5…
## $ a2 <dbl> 5, 5, 5, 5, 4, 3, 4, 3, 5, 5, 5, 4, 3, 5, 4, 5…
## $ a3 <dbl> 1, 2, 5, 5, 3, 1, 4, 1, 2, 4, 1, 4, 1, 4, 3, 1…
## $ a4 <dbl> 5, 5, 5, 5, 4, 5, 4, 5, 5, 4, 5, 4, 5, 5, 5, 5…
## $ a5 <dbl> 1, 3, 5, 1, 4, 4, 4, 1, 3, 4, 3, 4, 1, 4, 3, 1…
## $ p1 <dbl> 5, 3, 5, 5, 1, 4, 3, 3, 3, 2, 4, 1, 4, 4, 3, 5…
## $ p2 <dbl> 2, 0, 3, 3, 0, 2, 0, 2, 2, 0, 3, 0, 3, 3, 1, 4…
## $ p3 <dbl> 3, 0, 2, 3, 0, 3, 0, 2, 2, 0, 3, 0, 4, 2, 1, 2…
## $ p4 <dbl> 5, 1, 5, 3, 1, 3, 1, 3, 3, 1, 5, 2, 4, 5, 5, 5…
## $ p5 <dbl> 5, 1, 3, 2, 3, 3, 3, 2, 5, 3, 4, 2, 4, 4, 1, 3…
## $ dosis <dbl> 3, 3, 4, 3, 2, 2, 2, 1, 4, 3, 2, 4, 3, 1, 4, 2…
## $ razon_nv <chr> "Razon 5", "Razon 6", "Razon 1", "Razon 6", "R…
## $ periodico <chr> "Si", "No", "No", "Si", "No", "Si", "No", "No"…
## $ television <chr> "Si", "Si", "Si", "Si", "No", "Si", "Si", "Si"…
## $ redes_sociales <chr> "No", "Si", "Si", "No", "Si", "No", "Si", "Si"…
## $ personal_salud <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ radio <chr> "Si", "No", "Si", "No", "No", "Si", "No", "No"…
## $ paginas_internet <chr> "No", "No", "Si", "Si", "No", "No", "No", "No"…
## $ escuela <chr> "Si", "No", "No", "No", "No", "No", "No", "No"…
## $ mensajes <chr> "Si", "Si", "Si", "Si", "Si", "Si", "Si", "Si"…
## $ patrocinio <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ uso_de_mascarilla <chr> "Si", "Si", "Si", "Si", "No", "No", "No", "No"…
## $ distanciamiento_social <chr> "Si", "No", "Si", "Si", "Si", "No", "Si", "No"…
## $ lavado_de_manos <chr> "No", "Si", "Si", "No", "Si", "No", "Si", "No"…
## $ ponerse_la_vacuna <chr> "Si", "No", "No", "Si", "Si", "No", "No", "No"…
## $ no_recuerdo <chr> "No", "No", "No", "No", "No", "No", "No", "Si"…
## $ todas <chr> "No", "No", "No", "No", "No", "Si", "No", "No"…
## $ No_he_escuchado <chr> "No", "No", "No", "No", "No", "No", "No", "No"…
## $ transmite_por_el_agua <chr> "Si", "No", "No", "Si", "No", "Si", "No", "Si"…
## $ transmite_en_las_suelas <chr> "Si", "No", "No", "Si", "No", "Si", "No", "Si"…
## $ rociar_desinfectantes <chr> "Si", "No", "Si", "Si", "No", "Si", "No", "Si"…
## $ beben_alcohol <chr> "No", "No", "No", "Si", "No", "No", "No", "No"…
## $ pueden_dejar_de_aplicar <chr> "Si", "No", "No", "No", "No", "No", "No", "Si"…
## $ no_se_debe_vacunar <chr> "No", "No", "Si", "Si", "Si", "No", "Si", "No"…
## $ producen_esterilidad <chr> "No", "No", "No", "No", "No", "No", "Si", "No"…
## $ producen_homosexualidad <chr> "No", "Si", "No", "No", "No", "No", "No", "No"…
## $ inyectan_el_virus <chr> "No", "No", "Si", "Si", "No", "Si", "No", "No"…
## $ antibioticos_son_buenos <chr> "No", "No", "No", "Si", "No", "Si", "No", "Si"…
## $ vitaminas_y_minerales <chr> "No", "No", "No", "No", "No", "No", "No", "Si"…
## $ entrevistadoras <dbl> 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2…
## $ puntaje_A <dbl> 17, 19, 25, 21, 19, 16, 20, 13, 17, 22, 17, 20…
## $ c1recod <dbl> 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1…
## $ c2recod <dbl> 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ c3recod <dbl> 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0…
## $ c4recod <dbl> 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0…
## $ c5recod <dbl> 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ c6recod <dbl> 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0…
## $ c7recod <dbl> 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1…
## $ c8recod <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1…
## $ c9recod <dbl> 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
## $ c10recod <dbl> 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0…
## $ puntaje_C <dbl> 5, 8, 6, 8, 8, 8, 9, 5, 6, 9, 6, 8, 5, 5, 5, 5…
## $ puntaje_P <dbl> 20, 5, 18, 16, 5, 15, 7, 12, 15, 6, 19, 5, 19,…
# Vemos un resumen de los datos
summary(CAP_modif)
## id part_prev municipio edad
## Min. : 1.0 Length:515 Length:515 Min. :19.00
## 1st Qu.:129.5 Class :character Class :character 1st Qu.:30.00
## Median :258.0 Mode :character Mode :character Median :40.00
## Mean :258.0 Mean :42.37
## 3rd Qu.:386.5 3rd Qu.:55.00
## Max. :515.0 Max. :89.00
## genero nivel_edu enf_cro hipertension
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## diabetes epoc renal artritis
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## cardiopatia hipotiroidismo glaucoma lupus
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## ulcera_venosa ninguna area hijxs
## Length:515 Mode:logical Length:515 Length:515
## Class :character NA's:515 Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## nucleo empleo ocupacion ingreso
## Min. : 1.00 Length:515 Length:515 Length:515
## 1st Qu.: 3.00 Class :character Class :character Class :character
## Median : 4.00 Mode :character Mode :character Mode :character
## Mean : 5.67
## 3rd Qu.: 5.00
## Max. :999.00
## prev_per rec_apoyo satisfaccion prev_fam
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## mortalidad c1 c2 c3
## Length:515 Min. :1.000 Min. :1.000 Min. :1.000
## Class :character 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:1.000
## Mode :character Median :1.000 Median :1.000 Median :1.000
## Mean :1.066 Mean :1.151 Mean :1.645
## 3rd Qu.:1.000 3rd Qu.:1.000 3rd Qu.:2.000
## Max. :3.000 Max. :3.000 Max. :3.000
## c4 c5 c6 c7 c8
## Min. :1.000 Min. :1.000 Min. :1.000 Min. :1.00 Min. :1.000
## 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:1.00 1st Qu.:1.000
## Median :1.000 Median :2.000 Median :1.000 Median :2.00 Median :1.000
## Mean :1.171 Mean :2.155 Mean :1.301 Mean :1.94 Mean :1.037
## 3rd Qu.:1.000 3rd Qu.:3.000 3rd Qu.:2.000 3rd Qu.:3.00 3rd Qu.:1.000
## Max. :3.000 Max. :3.000 Max. :3.000 Max. :3.00 Max. :3.000
## c9 c10 a1 a2 a3
## Min. :1.000 Min. :1.000 Min. :2.000 Min. :1.000 Min. :1.00
## 1st Qu.:1.000 1st Qu.:1.000 1st Qu.:3.000 1st Qu.:3.000 1st Qu.:1.00
## Median :1.000 Median :2.000 Median :4.000 Median :4.000 Median :2.00
## Mean :1.091 Mean :2.062 Mean :3.986 Mean :4.033 Mean :2.25
## 3rd Qu.:1.000 3rd Qu.:3.000 3rd Qu.:5.000 3rd Qu.:5.000 3rd Qu.:3.00
## Max. :3.000 Max. :3.000 Max. :5.000 Max. :5.000 Max. :5.00
## a4 a5 p1 p2 p3
## Min. :1.000 Min. :1.00 Min. :0.000 Min. :0.000 Min. :0.000
## 1st Qu.:3.000 1st Qu.:2.00 1st Qu.:1.000 1st Qu.:0.500 1st Qu.:0.000
## Median :4.000 Median :3.00 Median :2.000 Median :1.000 Median :1.000
## Mean :3.808 Mean :2.75 Mean :2.468 Mean :1.579 Mean :1.524
## 3rd Qu.:5.000 3rd Qu.:3.00 3rd Qu.:4.000 3rd Qu.:3.000 3rd Qu.:3.000
## Max. :5.000 Max. :5.00 Max. :5.000 Max. :5.000 Max. :5.000
## p4 p5 dosis razon_nv
## Min. :0.000 Min. :0.000 Min. :0.000 Length:515
## 1st Qu.:1.000 1st Qu.:2.000 1st Qu.:2.000 Class :character
## Median :3.000 Median :3.000 Median :2.000 Mode :character
## Mean :2.936 Mean :3.103 Mean :2.355
## 3rd Qu.:5.000 3rd Qu.:4.000 3rd Qu.:3.000
## Max. :5.000 Max. :5.000 Max. :4.000
## periodico television redes_sociales personal_salud
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## radio paginas_internet escuela mensajes
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## patrocinio uso_de_mascarilla distanciamiento_social lavado_de_manos
## Mode:logical Length:515 Length:515 Length:515
## NA's:515 Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## ponerse_la_vacuna no_recuerdo todas No_he_escuchado
## Length:515 Length:515 Length:515 Length:515
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## transmite_por_el_agua transmite_en_las_suelas rociar_desinfectantes
## Length:515 Length:515 Length:515
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## beben_alcohol pueden_dejar_de_aplicar no_se_debe_vacunar
## Length:515 Length:515 Length:515
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## producen_esterilidad producen_homosexualidad inyectan_el_virus
## Length:515 Length:515 Length:515
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## antibioticos_son_buenos vitaminas_y_minerales entrevistadoras puntaje_A
## Length:515 Length:515 Min. :1.000 Min. : 8.00
## Class :character Class :character 1st Qu.:1.000 1st Qu.:15.00
## Mode :character Mode :character Median :2.000 Median :17.00
## Mean :1.736 Mean :16.83
## 3rd Qu.:2.000 3rd Qu.:18.00
## Max. :3.000 Max. :25.00
## c1recod c2recod c3recod c4recod
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:1.0000 1st Qu.:1.0000 1st Qu.:0.0000 1st Qu.:1.0000
## Median :1.0000 Median :1.0000 Median :1.0000 Median :1.0000
## Mean :0.9592 Mean :0.8854 Mean :0.5515 Mean :0.8932
## 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## c5recod c6recod c7recod c8recod
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:0.0000 1st Qu.:1.0000
## Median :0.0000 Median :1.0000 Median :0.0000 Median :1.0000
## Mean :0.3165 Mean :0.7456 Mean :0.4796 Mean :0.9806
## 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.0000
## c9recod c10recod puntaje_C puntaje_P
## Min. :0.0000 Min. :0.0000 Min. : 1.00 Min. : 0.00
## 1st Qu.:1.0000 1st Qu.:0.0000 1st Qu.: 6.00 1st Qu.: 7.00
## Median :1.0000 Median :0.0000 Median : 7.00 Median :11.00
## Mean :0.9301 Mean :0.3883 Mean : 7.13 Mean :11.61
## 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.: 9.00 3rd Qu.:16.00
## Max. :1.0000 Max. :1.0000 Max. :10.00 Max. :25.00
Antes de cualquier prueba, es fundamental entender nuestros datos.
Calculamos el número de observaciones, la media y la desviación estándar
del puntaje_C para cada nivel_edu.
str(CAP_modif$nivel_edu)
## chr [1:515] "Nunca asistio" "Primer ciclo" "Bachillerato" "Tercer ciclo" ...
CAP_modif$nivel_edu_factor <- as.factor(CAP_modif$nivel_edu)
table(CAP_modif$nivel_edu)
##
## Bachillerato Nunca asistio Primer ciclo Segundo ciclo Tecnico
## 185 22 48 81 20
## Tercer ciclo Universitario
## 117 42
CAP_modif %>%
group_by(nivel_edu) %>%
get_summary_stats(puntaje_C, type = "mean_sd")
## # A tibble: 7 × 5
## nivel_edu variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 Bachillerato puntaje_C 185 7.45 1.59
## 2 Nunca asistio puntaje_C 22 6.64 1.76
## 3 Primer ciclo puntaje_C 48 6.15 1.38
## 4 Segundo ciclo puntaje_C 81 6.74 1.51
## 5 Tecnico puntaje_C 20 7.25 1.07
## 6 Tercer ciclo puntaje_C 117 6.89 1.52
## 7 Universitario puntaje_C 42 8.48 1.64
Observación: A simple vista, las medias del
puntaje_C parecen aumentar con el nivel educativo. El ANOVA
nos dirá si estas diferencias observadas en la muestra son
estadísticamente significativas.
Un boxplot (diagrama de cajas y bigotes) es excelente para comparar distribuciones entre múltiples grupos.
ggboxplot(CAP_modif, x = "nivel_edu", y = "puntaje_C",
xlab = "Nivel Educativo",
ylab = "Puntaje C",
title = "Distribucion del Puntaje C por Nivel Educativo") +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas
Interpretación visual: El gráfico muestra una clara tendencia ascendente en las medianas (líneas gruesas) a medida que aumenta el nivel educativo. Las cajas (rangos intercuartílicos) tienen tamaños similares, lo que sugiere visualmente que las varianzas podrían ser homogéneas.
El ANOVA de una vía es robusto, pero funciona mejor cuando se cumplen tres supuestos:
puntaje_C deben ser iguales en todos los
grupos de nivel_edu.Identificamos outliers extremos que podrían sesgar los resultados.
outliers <- CAP_modif %>%
group_by(nivel_edu) %>%
identify_outliers(puntaje_C)
print(outliers)
## # A tibble: 7 × 95
## nivel_edu id part_prev municipio edad genero enf_cro hipertension diabetes
## <chr> <dbl> <chr> <chr> <dbl> <chr> <chr> <chr> <chr>
## 1 Bachille… 191 No Zaragoza 52 Mascu… No No No
## 2 Tecnico 120 No Santa Te… 42 Femen… No No No
## 3 Tecnico 207 No Zaragoza 31 Mascu… No No No
## 4 Universi… 297 Si Santa Te… 36 Femen… Si No No
## 5 Universi… 384 No Comasagua 49 Femen… No sabe No No
## 6 Universi… 395 No Comasagua 79 Mascu… Si No Si
## 7 Universi… 461 No Zaragoza 56 Mascu… No No No
## # ℹ 86 more variables: epoc <chr>, renal <chr>, artritis <chr>,
## # cardiopatia <chr>, hipotiroidismo <chr>, glaucoma <chr>, lupus <chr>,
## # ulcera_venosa <chr>, ninguna <lgl>, area <chr>, hijxs <chr>, nucleo <dbl>,
## # empleo <chr>, ocupacion <chr>, ingreso <chr>, prev_per <chr>,
## # rec_apoyo <chr>, satisfaccion <chr>, prev_fam <chr>, mortalidad <chr>,
## # c1 <dbl>, c2 <dbl>, c3 <dbl>, c4 <dbl>, c5 <dbl>, c6 <dbl>, c7 <dbl>,
## # c8 <dbl>, c9 <dbl>, c10 <dbl>, a1 <dbl>, a2 <dbl>, a3 <dbl>, a4 <dbl>, …
En nuestra simulación, no aparecieron outliers extremos (is_extreme = TRUE), así que continuamos.
Evaluamos la normalidad de los residuos del modelo.
# Construimos el modelo lineal (base del ANOVA)
modelo_anova <- lm(puntaje_C ~ nivel_edu, data = CAP_modif)
# Obtenemos los residuos
residuos_modelo <- residuals(modelo_anova)
# 1. Prueba de Shapiro-Wilk sobre los residuos
shapiro_test(residuos_modelo)
## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuos_modelo 0.973 0.0000000436
Interpretación (Shapiro-Wilk): La hipótesis nula (H₀) es que los datos (residuos) provienen de una distribución normal. Si p > 0.05, no podemos rechazar H₀ y asumimos normalidad. En nuestra simulación, el p-valor es alto, por lo que cumplimos el supuesto.
# 2. Gráfico Q-Q (Cuantil-Cuantil)
ggqqplot(residuos_modelo)
Interpretación (Q-Q Plot): Si los puntos se ajustan razonablemente bien a la línea diagonal, podemos asumir normalidad.
Usamos la Prueba de Levene para verificar si las varianzas entre los grupos son iguales.
# La H₀ es que las varianzas son iguales.
CAP_modif %>%
levene_test(puntaje_C ~ nivel_edu)
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 6 508 1.71 0.117
Interpretación (Levene): Buscamos un p-valor > 0.05. Si el p-valor es alto (como en nuestro caso), no rechazamos la H₀ y concluimos que las varianzas son homogéneas (Homocedasticidad).
Nota: Si el supuesto de homogeneidad no se cumple, se debe usar
el ANOVA de Welch (welch_anova_test()).
Dado que cumplimos ambos supuestos (Normalidad y Homocedasticidad), procedemos con el ANOVA estándar.
# Cargar la librería dplyr si no está cargada
library(dplyr)
# 1. Creamos un nuevo data frame filtrando todos los NAs
CAP_modif <- CAP_modif %>%
filter(
!is.na(puntaje_C), # Quitar filas donde el puntaje es NA
!is.na(nivel_edu) # Quitar filas donde el nivel es NA
)
# Usamos la función anova_test() de rstatix
resultado_anova <- CAP_modif %>%
anova_test(puntaje_C ~ nivel_edu)
# Mostramos el resultado
print(resultado_anova)
## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 nivel_edu 6 508 11.699 2.69e-12 * 0.121
La tabla ANOVA nos muestra: * DFn (Grados de libertad
Numerador): k - 1 = 7 grupos - 1 = 6 * DFd (Grados de
libertad Denominador): N - k = 210 - 7 = 203 * F
(Estadístico F): La proporción de varianza entre grupos /
varianza dentro de grupos. * p (p-valor): La
probabilidad de observar un valor F tan grande (o más) si la H₀ fuera
cierta. * ges (Eta-cuadrado generalizado): El tamaño
del efecto. Indica qué porcentaje de la varianza en
puntaje_C es explicado por nivel_edu. Un
ges de 0.54 (54%) es un efecto muy grande.
Conclusión del ANOVA: Obtuvimos un resultado de F(6,
203) = 39.4, con un p-valor < 0.0001 (indicado como
<2e-16 o ***).
Dado que p < 0.05, rechazamos la hipótesis nula
(H₀) de que todas las medias de puntaje_C son iguales entre
los 7 niveles educativos.
Conclusión estadística: Existe una diferencia
estadísticamente significativa en el puntaje_C promedio
entre al menos dos de los grupos de nivel_edu.
El ANOVA nos dijo que “hay una diferencia en algún lugar”, pero no nos dijo dónde. Para saber qué grupos específicos son diferentes entre sí, realizamos una prueba post-hoc. La más común cuando las varianzas son iguales es la Prueba HSD de Tukey.
# Realizamos la prueba HSD de Tukey
comparaciones_tukey <- CAP_modif %>%
tukey_hsd(puntaje_C ~ nivel_edu)
# Mostramos los resultados
# (Filtramos solo las comparaciones significativas para claridad, aunque es bueno verlas todas)
comparaciones_tukey %>%
filter(p.adj < 0.05) %>%
print(n = 15) # Imprime las primeras 15 filas significativas
## # A tibble: 8 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 nivel_edu Bachillerato Prime… 0 -1.30 -2.04 -0.565 5.19e- 6
## 2 nivel_edu Bachillerato Segun… 0 -0.708 -1.31 -0.101 1.07e- 2
## 3 nivel_edu Bachillerato Terce… 0 -0.560 -1.10 -0.0219 3.52e- 2
## 4 nivel_edu Bachillerato Unive… 0 1.03 0.249 1.81 2.03e- 3
## 5 nivel_edu Nunca asistio Unive… 0 1.84 0.641 3.04 1.4 e- 4
## 6 nivel_edu Primer ciclo Unive… 0 2.33 1.37 3.29 2.3 e-10
## 7 nivel_edu Segundo ciclo Unive… 0 1.74 0.870 2.60 1.15e- 7
## 8 nivel_edu Tercer ciclo Unive… 0 1.59 0.768 2.41 3.48e- 7
## # ℹ 1 more variable: p.adj.signif <chr>
La tabla comparaciones_tukey nos muestra todas las
comparaciones “dos a dos” (21 comparaciones en total para 7 grupos).
group1, group2: Los dos grupos que se comparan.
p.adj (p-valor ajustado): El p-valor ajustado para las comparaciones múltiples.
p.adj.signif: Una guía rápida de significancia
(*, **, ***).
Conclusión (basada en la simulación): Vemos que casi todas las comparaciones son significativas (p.adj < 0.05), excepto aquellas entre grupos adyacentes (ej. “Primaria” vs “Secundaria”, “Bachillerato” vs “Técnico”). Esto significa que, aunque la tendencia general es que a más educación, más puntaje, la diferencia entre niveles “contiguos” no siempre es estadísticamente significativa.
Podemos añadir los resultados de las comparaciones (p-valores ajustados) a nuestro boxplot inicial para un resumen gráfico completo.
# --- CÓDIGO 100% LIMPIO PARA EL GRÁFICO (SECCIÓN 8) ---
table(CAP_modif$nivel_edu)
##
## Bachillerato Nunca asistio Primer ciclo Segundo ciclo Tecnico
## 185 22 48 81 20
## Tercer ciclo Universitario
## 117 42
# 1. Asignar el resultado post-hoc
# (Asegurarse de que "comparaciones_tukey" se creo en la Sección 7)
comparaciones_finales <- comparaciones_tukey %>%
mutate(y.position = seq(1.2 * max(CAP_modif$puntaje_C),
1.2 * max(CAP_modif$puntaje_C) + 0.5 * n(),
length.out = n()))
# 2. Crear el gráfico (Versión corregida y limpia)
ggboxplot(
CAP_modif,
x = "nivel_edu", # Usando su variable factor (como usted indico)
y = "puntaje_C",
xlab = "Nivel Educativo",
ylab = "Puntaje C",
title = "Comparacion del Puntaje C por Nivel Educativo (ANOVA)"
) +
stat_pvalue_manual(
comparaciones_finales,
label = "p.adj.signif",
step.increase = 0.08, # R ahora vera este argumento
hide.ns = FALSE
) +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
puntaje_C.¡Es su turno de aplicar lo aprendido! El objetivo es que realice el
proceso completo de ANOVA de una vía (desde la preparación hasta la
interpretación) para investigar si existen diferencias en el
puntaje_C (conocimientos) según diferentes
variables categóricas de la base CAP_modif.
Deberá realizar cinco (5) análisis ANOVA completos.
La variable dependiente (numérica) siempre será puntaje_C.
Las variables independientes (categóricas) serán:
etario (una nueva variable que debe
crear)municipioempleoocupacioningresoetarioEl primer paso es crear la variable etario (grupo de
edad) a partir de la variable numérica edad. Copie y
ejecute este código en un nuevo chunk para añadir la columna a
su CAP_modif.
library(dplyr)
# Asumimos que la base de datos se llama "CAP_modif"
# y la variable de edad es "edad" (ajuste si es necesario)
CAP_modif <- CAP_modif %>%
mutate(
# case_when() es perfecto para crear grupos
etario = case_when(
edad >= 18 & edad <= 29 ~ "18 a 29 años",
edad >= 30 & edad <= 44 ~ "30 a 44 años",
edad >= 45 & edad <= 64 ~ "45 a 64 años",
edad >= 65 ~ "65 y más años",
TRUE ~ NA_character_ # Asigna NA si es < 18 o no cumple
),
# Convertimos la nueva variable a factor
etario = factor(etario)
)
# Verificamos la creación de la variable
cat("Grupos de edad creados:\n")
## Grupos de edad creados:
table(CAP_modif$etario, useNA = "ifany")
##
## 18 a 29 años 30 a 44 años 45 a 64 años 65 y más años
## 126 177 154 58
Para cada uno de los 5 análisis
(etario, municipio, empleo,
etc.), debe seguir y documentar esta lista de chequeo:
filter()) que elimine las filas con
NA tanto en puntaje_C como en la variable
categórica que está analizando (ej. !is.na(empleo)).table() sobre sus datos limpios. ¿Tiene algún grupo con
N < 2 (cero o un participante)? Si es así, Tukey
fallará. Debe filtrar esos grupos antes de continuar.ggboxplot() para visualizar las
distribuciones.get_summary_stats()).levene_test(). ¿Se cumple (p > 0.05)?shapiro_test()
sobre los residuos del modelo
(residuals(lm(...))).anova_test() (si Levene
OK) o welch_anova_test() (si Levene p < 0.05)?tukey_hsd() (para ANOVA
estándar) o games_howell_test() (para Welch)?ggboxplot final, añadiendo las etiquetas de
p-valor con stat_pvalue_manual().¡Éxito en su análisis!