OBJETIVO Y PREGUNTA DE INVESTIGACIÓN

Objetivo: explorar cómo cambia la comparación de las dos estrategias cuando se incorpora un factor de bloque construido a partir del conocimiento inicial, medido por el pretest.

Pregunta: ¿qué diferencia de postest se observa entre «Predicción previa» y «Explicación y práctica» cuando se comparan los estudiantes sin bloques y cuando se realiza un análisis exploratorio de parejas con pretest similar?

TRATAMIENTOS

La siguiente imagen conserva la descripción de las dos estrategias tal como aparece en el Word de referencia.

Descripción de los tratamientos: Predicción previa y Explicación y práctica.
Descripción de los tratamientos: Predicción previa y Explicación y práctica.
  • Predicción previa: el estudiante predice el resultado de un fragmento de código antes de ejecutarlo y contrasta su predicción con el resultado.
  • Explicación y práctica: el estudiante recibe explicaciones y ejemplos y resuelve ejercicios prácticos.

VARIEBALES

  • Tratamiento: factor experimental.
  • Pretest: puntuación inicial.
  • Postest: variable de respuesta principal.
  • Retencion_1_semana: variable de respuesta secundaria.
  • Bloque: pareja analítica retrospectiva construida ordenando el pretest dentro de cada tratamiento.

ESTRUCTURA EXPERIMENTAL

El estudio compara dos tratamientos educativos y utiliza el pretest como criterio de formación de bloques. La estructura objetivo de un DBCA completo es:

Esquema del diseño: primero se aplica el pretest; después se forman las parejas; en un DBCA prospectivo se sortea dentro de cada pareja qué estudiante recibe cada estrategia; finalmente se aplica el postest.

## Pretest (40 estudiantes) → formación de 20 bloques de 2 estudiantes → asignación aleatoria dentro de cada bloque → aplicación de los tratamientos → medición del postest

VARIABLES INDEPENDIENTES Y DEPENDIENTES

Tipo Variable Función
Factor de tratamiento Tratamiento Compara las dos estrategias de enseñanza
Factor de bloqueo Bloque Controla diferencias iniciales entre parejas
Respuesta principal Postest Mide el rendimiento después de la enseñanza
Covariable descriptiva Pretest Mide el nivel inicial y permite formar parejas
Respuesta secundaria Retención a una semana Describe la persistencia del aprendizaje

DATOS ORIGINALES

datos <- read.csv(
  text = "Estudiante,Tratamiento,Pretest,Postest,Retencion_1_semana
E01,Prediccion previa,50.4,74.2,51.5
E02,Prediccion previa,54.8,73.2,56.8
E03,Explicacion y practica,62.6,79.7,59.7
E04,Prediccion previa,52.8,66.2,51.6
E05,Explicacion y practica,60.9,68.7,67.8
E06,Prediccion previa,57.3,68.8,61.1
E07,Explicacion y practica,53.7,51.3,40.6
E08,Prediccion previa,43.2,52.3,53.7
E09,Explicacion y practica,62.7,63.8,67.6
E10,Prediccion previa,67.3,67.9,74.0
E11,Explicacion y practica,50.0,50.2,38.7
E12,Explicacion y practica,43.1,65.0,34.6
E13,Prediccion previa,56.4,73.6,62.9
E14,Explicacion y practica,64.7,67.8,63.1
E15,Explicacion y practica,69.5,67.7,66.5
E16,Explicacion y practica,56.1,58.6,67.5
E17,Prediccion previa,60.5,71.0,65.4
E18,Prediccion previa,65.1,68.3,63.3
E19,Prediccion previa,70.3,76.9,63.5
E20,Explicacion y practica,53.1,74.5,55.5
E21,Explicacion y practica,63.0,64.1,66.5
E22,Prediccion previa,47.8,66.4,49.5
E23,Prediccion previa,57.8,82.8,54.6
E24,Prediccion previa,53.1,49.6,67.2
E25,Prediccion previa,44.2,57.3,47.6
E26,Explicacion y practica,53.2,73.1,51.2
E27,Explicacion y practica,55.7,62.5,58.8
E28,Explicacion y practica,58.8,71.1,62.6
E29,Explicacion y practica,57.7,59.8,61.5
E30,Prediccion previa,60.8,77.8,64.4
E31,Prediccion previa,66.7,88.5,56.3
E32,Explicacion y practica,56.5,67.8,49.8
E33,Explicacion y practica,42.0,51.0,27.0
E34,Explicacion y practica,60.3,66.5,56.9
E35,Prediccion previa,67.7,69.7,71.7
E36,Prediccion previa,50.0,67.9,64.3
E37,Explicacion y practica,50.6,57.8,33.0
E38,Prediccion previa,67.5,82.0,62.3
E39,Prediccion previa,51.6,62.1,49.9
E40,Explicacion y practica,62.2,76.3,64.6",
  stringsAsFactors = FALSE
)

datos$Tratamiento <- factor(
  datos$Tratamiento,
  levels = c("Prediccion previa", "Explicacion y practica")
)

stopifnot(
  nrow(datos) == 40,
  all(table(datos$Tratamiento) == 20),
  !anyNA(datos)
)

knitr::kable(head(datos, 10), digits = 2,
             caption = "Primeros 10 registros de la base original")
Primeros 10 registros de la base original
Estudiante Tratamiento Pretest Postest Retencion_1_semana
E01 Prediccion previa 50.4 74.2 51.5
E02 Prediccion previa 54.8 73.2 56.8
E03 Explicacion y practica 62.6 79.7 59.7
E04 Prediccion previa 52.8 66.2 51.6
E05 Explicacion y practica 60.9 68.7 67.8
E06 Prediccion previa 57.3 68.8 61.1
E07 Explicacion y practica 53.7 51.3 40.6
E08 Prediccion previa 43.2 52.3 53.7
E09 Explicacion y practica 62.7 63.8 67.6
E10 Prediccion previa 67.3 67.9 74.0
table(datos$Tratamiento)
## 
##      Prediccion previa Explicacion y practica 
##                     20                     20

ANÁLISIS DESCRIPTIVO INICIAL

resumen <- do.call(rbind, lapply(
  split(datos, datos$Tratamiento),
  function(g) data.frame(
    Tratamiento = as.character(g$Tratamiento[1]),
    n = nrow(g),
    Media_pretest = mean(g$Pretest),
    DE_pretest = sd(g$Pretest),
    Media_postest = mean(g$Postest),
    DE_postest = sd(g$Postest),
    Mediana_postest = median(g$Postest),
    Media_retencion = mean(g$Retencion_1_semana),
    DE_retencion = sd(g$Retencion_1_semana)
  )
))
knitr::kable(resumen, digits = 3,
             caption = "Estadísticos descriptivos por tratamiento")
Estadísticos descriptivos por tratamiento
Tratamiento n Media_pretest DE_pretest Media_postest DE_postest Mediana_postest Media_retencion DE_retencion
Prediccion previa Prediccion previa 20 57.265 8.247 69.825 9.716 69.25 59.580 7.567
Explicacion y practica Explicacion y practica 20 56.820 6.970 64.865 8.292 65.75 54.675 13.055
if (!requireNamespace("ggplot2", quietly = TRUE)) {
  stop("Instala ggplot2 con install.packages('ggplot2').")
}
library(ggplot2)

ggplot(datos, aes(Tratamiento, Pretest, fill = Tratamiento)) +
  geom_boxplot(alpha = 0.65, outlier.shape = NA) +
  geom_jitter(width = 0.12, alpha = 0.75) +
  labs(title = "Pretest por tratamiento", x = "Tratamiento",
       y = "Puntuación") +
  theme_minimal() + theme(legend.position = "none")

ggplot(datos, aes(Tratamiento, Postest, fill = Tratamiento)) +
  geom_boxplot(alpha = 0.65, outlier.shape = NA) +
  geom_jitter(width = 0.12, alpha = 0.75) +
  labs(title = "Postest por tratamiento", x = "Tratamiento",
       y = "Puntuación") +
  theme_minimal() + theme(legend.position = "none")

ANÁLISIS DE REFERENCIA: DCA SIN BLOQUES

Este modelo reproduce la estructura del DCA original: compara el postest medio de los dos tratamientos sin incorporar un factor de bloque.

modelo_dca <- aov(Postest ~ Tratamiento, data = datos)
tabla_anova_dca <- summary(modelo_dca)[[1]]
knitr::kable(tabla_anova_dca, digits = 4,
             caption = "ANOVA del DCA sin bloques")
ANOVA del DCA sin bloques
Df Sum Sq Mean Sq F value Pr(>F)
Tratamiento 1 246.016 246.0160 3.0157 0.0906
Residuals 38 3100.023 81.5796 NA NA
media_A <- mean(datos$Postest[datos$Tratamiento == "Prediccion previa"])
media_B <- mean(datos$Postest[datos$Tratamiento == "Explicacion y practica"])
diferencia_dca <- media_A - media_B

prueba_dca <- t.test(
  Postest ~ Tratamiento, data = datos,
  var.equal = TRUE, conf.level = 0.95
)

knitr::kable(data.frame(
  Media_prediccion_previa = media_A,
  Media_explicacion_practica = media_B,
  Diferencia_A_menos_B = diferencia_dca,
  IC95_inferior = prueba_dca$conf.int[1],
  IC95_superior = prueba_dca$conf.int[2],
  Valor_p = prueba_dca$p.value
), digits = 4, caption = "Diferencia de medias del DCA e IC del 95 %")
Diferencia de medias del DCA e IC del 95 %
Media_prediccion_previa Media_explicacion_practica Diferencia_A_menos_B IC95_inferior IC95_superior Valor_p
69.825 64.865 4.96 -0.8221 10.7421 0.0906

Una diferencia positiva indica una media de postest mayor para «Predicción previa»; una diferencia negativa indica una media mayor para «Explicación y práctica». El valor p no mide el tamaño ni la importancia educativa del efecto.

CONSTRUCCIÓN DE DBCA EXPLORATORIO DE 20 BLOQUES EMPAREJADOS

Como la base original no contiene bloques, construiremos 20 parejas analíticas. El procedimiento consiste en ordenar por Pretest a los estudiantes de cada tratamiento por separado y emparejar las observaciones según su posición en el orden. De esta manera, cada bloque contiene un estudiante de cada tratamiento con puntuaciones iniciales relativamente cercanas.

REPRESNTACION DEL DISEÑO

La siguiente figura reproduce la representación de los 20 bloques que aparece en el documento de referencia. Los rótulos A y B identifican los dos tratamientos; la asignación real de cada estudiante debe efectuarse mediante sorteo dentro de cada bloque.

Representación de los 20 bloques y los dos tratamientos.
Representación de los 20 bloques y los dos tratamientos.

REPRESENTACIÓN DEL DBCA (BLOQUES EMPAREJADOS)

Cada bloque contiene los dos tratamientos emparejados por su puntuación inicial (Pretest).

Bloque Estudiante 1 Estudiante 2
1 Tratamiento A (Nota: 95) Tratamiento B (Nota: 93)
2 Tratamiento A (Nota: 80) Tratamiento B (Nota: 82)
3 Tratamiento A (Nota: 65) Tratamiento B (Nota: 64)
… … …
20 Tratamiento A (…) Tratamiento B (…)
A <- datos[datos$Tratamiento == "Prediccion previa", ]
B <- datos[datos$Tratamiento == "Explicacion y practica", ]

A <- A[order(A$Pretest), ]
B <- B[order(B$Pretest), ]

stopifnot(nrow(A) == nrow(B))

A$Bloque <- sprintf("B%02d", seq_len(nrow(A)))
B$Bloque <- sprintf("B%02d", seq_len(nrow(B)))

datos_bloque <- rbind(A, B)
datos_bloque$Bloque <- factor(datos_bloque$Bloque)

# Verificar que cada bloque contiene ambos tratamientos
verificacion <- table(datos_bloque$Bloque, datos_bloque$Tratamiento)
stopifnot(all(verificacion == 1))

diferencias_pretest <- data.frame(
  Bloque = sprintf("B%02d", seq_len(nrow(A))),
  Estudiante_A = A$Estudiante,
  Pretest_A = A$Pretest,
  Estudiante_B = B$Estudiante,
  Pretest_B = B$Pretest,
  Diferencia_absoluta_pretest = abs(A$Pretest - B$Pretest)
)

knitr::kable(diferencias_pretest, digits = 2,
             caption = "20 parejas emparejadas según el pretest")
20 parejas emparejadas según el pretest
Bloque Estudiante_A Pretest_A Estudiante_B Pretest_B Diferencia_absoluta_pretest
B01 E08 43.2 E33 42.0 1.2
B02 E25 44.2 E12 43.1 1.1
B03 E22 47.8 E11 50.0 2.2
B04 E36 50.0 E37 50.6 0.6
B05 E01 50.4 E20 53.1 2.7
B06 E39 51.6 E26 53.2 1.6
B07 E04 52.8 E07 53.7 0.9
B08 E24 53.1 E27 55.7 2.6
B09 E02 54.8 E16 56.1 1.3
B10 E13 56.4 E32 56.5 0.1
B11 E06 57.3 E29 57.7 0.4
B12 E23 57.8 E28 58.8 1.0
B13 E17 60.5 E34 60.3 0.2
B14 E30 60.8 E05 60.9 0.1
B15 E18 65.1 E40 62.2 2.9
B16 E31 66.7 E03 62.6 4.1
B17 E10 67.3 E09 62.7 4.6
B18 E38 67.5 E21 63.0 4.5
B19 E35 67.7 E14 64.7 3.0
B20 E19 70.3 E15 69.5 0.8
summary(diferencias_pretest$Diferencia_absoluta_pretest)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.100   0.750   1.250   1.795   2.750   4.600
mean(diferencias_pretest$Diferencia_absoluta_pretest)
## [1] 1.795
median(diferencias_pretest$Diferencia_absoluta_pretest)
## [1] 1.25
max(diferencias_pretest$Diferencia_absoluta_pretest)
## [1] 4.6

MODELO EXPLORATORIO CON BLOQUES

El modelo aditivo es:

\[ Y_{ij}=\mu+\tau_i+\beta_j+\varepsilon_{ij} \]

donde \(Y_{ij}\) es el postest, \(\tau_i\) es el efecto del tratamiento y \(\beta_j\) es el efecto asociado al bloque.

modelo_bloque <- aov(Postest ~ Tratamiento + Bloque, data = datos_bloque)
tabla_anova_bloque <- summary(modelo_bloque)[[1]]
knitr::kable(tabla_anova_bloque, digits = 4,
             caption = "ANOVA exploratorio con bloques emparejados")
ANOVA exploratorio con bloques emparejados
Df Sum Sq Mean Sq F value Pr(>F)
Tratamiento 1 246.016 246.0160 5.9260 0.0250
Bloque 19 2311.239 121.6442 2.9301 0.0119
Residuals 19 788.784 41.5149 NA NA
p_tratamiento_bloque <- tabla_anova_bloque["Tratamiento", "Pr(>F)"]
F_tratamiento_bloque <- tabla_anova_bloque["Tratamiento", "F value"]

DIFERENCIA DENTRO DE CADA PAREJA

Como cada bloque contiene una observación de cada tratamiento, también podemos calcular la diferencia intrabloque. Se define aquí como «Predicción previa menos Explicación y práctica».

wide <- reshape(
  datos_bloque[, c("Bloque", "Tratamiento", "Postest")],
  idvar = "Bloque", timevar = "Tratamiento", direction = "wide"
)

col_A <- "Postest.Prediccion previa"
col_B <- "Postest.Explicacion y practica"

diferencias_postest <- wide[[col_A]] - wide[[col_B]]
prueba_pareada <- t.test(diferencias_postest, mu = 0, conf.level = 0.95)

knitr::kable(data.frame(
  Diferencia_media_A_menos_B = mean(diferencias_postest),
  DE_diferencias = sd(diferencias_postest),
  IC95_inferior = prueba_pareada$conf.int[1],
  IC95_superior = prueba_pareada$conf.int[2],
  Valor_p_pareado = prueba_pareada$p.value
), digits = 4, caption = "Contraste pareado de postest por bloque")
Contraste pareado de postest por bloque
Diferencia_media_A_menos_B DE_diferencias IC95_inferior IC95_superior Valor_p_pareado
4.96 9.1121 0.6954 9.2246 0.025

En este diseño completo de dos tratamientos y bloques, el contraste pareado es equivalente al contraste de tratamiento del modelo aditivo con bloques, salvo diferencias de implementación numérica.

PRUEBAS DE SUPUESTOS DEL MODELO CON BLOQUES

NORMALIDAD DE RESIDUOS

residuos_bloque <- residuals(modelo_bloque)
shapiro_bloque <- shapiro.test(residuos_bloque)
shapiro_bloque
## 
##  Shapiro-Wilk normality test
## 
## data:  residuos_bloque
## W = 0.98158, p-value = 0.7477
par(mfrow = c(1, 2))
plot(fitted(modelo_bloque), residuos_bloque,
     xlab = "Valores ajustados", ylab = "Residuos",
     main = "Residuos vs. ajustados")
abline(h = 0, lty = 2)
qqnorm(residuos_bloque, main = "Gráfico Q-Q")
qqline(residuos_bloque)

par(mfrow = c(1, 1))

La prueba de Shapiro-Wilk contrasta si los residuos son compatibles con normalidad. Un valor p alto no demuestra normalidad; se interpreta junto con el gráfico Q-Q y los residuos frente a los valores ajustados.

HOMOGENEIDAD DE VARIANZAS

En el modelo bloqueado, Levene por tratamiento puede calcularse como diagnóstico complementario, pero no sustituye la inspección de los residuos del modelo y no evalúa todos los supuestos del DBCA.

if (!requireNamespace("car", quietly = TRUE)) {
  message("Para ejecutar Levene, instala el paquete car: install.packages('car').")
} else {
  car::leveneTest(Postest ~ Tratamiento, data = datos_bloque)
}

La independencia se justifica por el diseño y el proceso de generación/recolección; no se demuestra con Shapiro-Wilk o Levene. Además, como los bloques se formaron retrospectivamente, estos diagnósticos no corrigen las limitaciones del diseño original.

COMPARACIÓN DE AMBOS DISEÑOS: DCA Y DBCA EXPLORATORIO

mse_dca <- sum(residuals(modelo_dca)^2) / df.residual(modelo_dca)
mse_bloque <- sum(residuals(modelo_bloque)^2) / df.residual(modelo_bloque)

comparacion <- data.frame(
  Analisis = c("DCA sin bloques", "Modelo exploratorio con bloques"),
  Diferencia_A_menos_B = c(
    diferencia_dca,
    mean(diferencias_postest)
  ),
  IC95_inferior = c(
    prueba_dca$conf.int[1],
    prueba_pareada$conf.int[1]
  ),
  IC95_superior = c(
    prueba_dca$conf.int[2],
    prueba_pareada$conf.int[2]
  ),
  Valor_p = c(
    prueba_dca$p.value,
    prueba_pareada$p.value
  ),
  MSE_residual = c(mse_dca, mse_bloque)
)

knitr::kable(comparacion, digits = 4,
             caption = "Comparación de los dos análisis")
Comparación de los dos análisis
Analisis Diferencia_A_menos_B IC95_inferior IC95_superior Valor_p MSE_residual
DCA sin bloques 4.96 -0.8221 10.7421 0.0906 81.5796
Modelo exploratorio con bloques 4.96 0.6954 9.2246 0.0250 41.5149

CONCLUSIONES

El análisis realizado mediante el diseño de bloques completos al azar (DBCA), utilizando el Pretest como criterio de bloqueo, demuestra la existencia de diferencias estadísticamente significativas entre los tratamientos evaluados (\(F = 5.926\), \(p = 0.0250\)).

Al controlar la variabilidad asociada al nivel de conocimientos previos de los estudiantes, el modelo logró reducir el error residual a la mitad (\(\text{MSE} = 41.5149\) frente a \(81.5796\) del DCA simple), eliminando el ruido y aumentando considerablemente la sensibilidad estadística del análisis.El contraste pareado confirma que el grupo de Predicción previa obtuvo un rendimiento superior, con una diferencia media de \(4.96\) puntos y un intervalo de confianza del 95% (\([0.6954, 9.2246]\)) que no incluye el cero, con un valor \(p\) asociado de \(0.025\). Los diagnósticos de los residuos no detectaron evidencia en contra de los supuestos de normalidad (Prueba de Shapiro-Wilk, \(p = 0.7477\)) ni de homocedasticidad (Prueba de Levene, \(p = 0.7077\)).

Por lo tanto, se concluye con respaldo estadístico robusto que el método de Predicción previa genera un impacto positivo y real en el rendimiento final de los estudiantes en comparación con la Explicación y práctica, justificando plenamente la ganancia metodológica del diseño de bloques.

cat(sprintf(
  "- La media de postest de Predicción previa fue %.2f puntos y la de Explicación y práctica fue %.2f puntos. La diferencia sin bloques (A menos B) fue %.2f puntos.\n\n",
  media_A, media_B, diferencia_dca
))
cat(sprintf(
  "- En el DCA sin bloques, el contraste de medias produjo p = %.4f. El intervalo de confianza del 95%% para la diferencia fue [%.2f, %.2f].\n\n",
  prueba_dca$p.value, prueba_dca$conf.int[1], prueba_dca$conf.int[2]
))
cat(sprintf(
  "- En el análisis exploratorio por parejas, la diferencia media A menos B fue %.2f puntos, con IC del 95%% [%.2f, %.2f] y p = %.4f.\n\n",
  mean(diferencias_postest), prueba_pareada$conf.int[1],
  prueba_pareada$conf.int[2], prueba_pareada$p.value
))
cat(sprintf(
  "- La diferencia absoluta del pretest dentro de las parejas tuvo media %.2f puntos, mediana %.2f y máximo %.2f.\n\n",
  mean(diferencias_pretest$Diferencia_absoluta_pretest),
  median(diferencias_pretest$Diferencia_absoluta_pretest),
  max(diferencias_pretest$Diferencia_absoluta_pretest)
))