1 Objetivo y fuentes de datos

Este reporte entrega un panorama general y un diagnóstico de calidad/consistencia de tres fuentes actualizadas, restringido a los grados 2° Medio (2m) y 4° Básico (4b):

  1. Ensayos Santillana (consolidado_ensayo_simce.parquet): resultados a nivel de alumno-evaluación (porcentaje de logro, 0–100).
  2. SIMCE a nivel colegio (consolidado_datos_simce_rbd.parquet): promedio SIMCE por RBD, año, grado y área, ahora con metadatos del establecimiento (comuna, dependencia, grupo socioeconómico, matrícula evaluada nalu).
  3. SIMCE a nivel alumno (consolidado_datos_simce_alu.parquet): puntajes individuales de matemática y lectura, con error de medición (eem_*) y estándar de aprendizaje (eda_*).

Respecto de la versión anterior, la fuente corrigió (i) la duplicación de una base SIMCE (2° medio 2024) y (ii) la lectura de separadores decimales que multiplicaba por 100 los puntajes 2024–2025. Este reporte verifica ambas correcciones y detecta un residuo menor del problema de decimales (sección de errores).

2 Carga de datos

# Configurar rutas de archivos: ----
rutas <- config::get(file = "config.yml")
ruta_data_in <- rutas$ruta_data_in
ruta_data_intermedia <- rutas$ruta_data_intermedia

simce_rbd <- ruta_data_intermedia |>  
  file.path('simce', 'consolidado_datos_simce_rbd.parquet') |> 
  arrow::read_parquet()
ensayos    <- ruta_data_intermedia |>  
  file.path('ensayo_simce', 'consolidado_ensayo_simce.parquet') |> 
  arrow::read_parquet()

simce_alu <- ruta_data_intermedia |>  
  file.path('simce', 'consolidado_datos_simce_alu.parquet') |> 
  arrow::read_parquet()

tibble(
  fuente = c("Ensayos Santillana", "SIMCE por RBD", "SIMCE por alumno"),
  filas = comma(c(nrow(ensayos), nrow(simce_rbd), nrow(simce_alu))),
  columnas = c(ncol(ensayos), ncol(simce_rbd), ncol(simce_alu))
) %>% kable(caption = "Dimensiones de las fuentes")
Dimensiones de las fuentes
fuente filas columnas
Ensayos Santillana 265,906 17
SIMCE por RBD 107,626 14
SIMCE por alumno 2,592,070 13

2.1 Verificación de las correcciones de la fuente

# 1) Duplicados en la base RBD (antes: ~6.000 en 2m-2024)
dup_rbd <- sum(duplicated(simce_rbd[, c("agno", "grado", "rbd", "area")]))

# 2) Escala de puntajes de alumno (antes: mediana ~19.500 en 2024-2025)
escala <- simce_alu %>%
  group_by(agno) %>%
  summarise(mediana_mate = median(ptje_mate, na.rm = TRUE),
            max_mate = max(ptje_mate, na.rm = TRUE),
            pct_sobre_1000 = mean(ptje_mate > 1000, na.rm = TRUE),
            pct_bajo_100 = mean(ptje_mate < 100, na.rm = TRUE),
            .groups = "drop")

kable(escala %>% mutate(across(starts_with("pct"), ~percent(.x, .01)),
                        across(c(mediana_mate, max_mate), ~round(.x, 1))),
      caption = sprintf("Verificación de escala (duplicados clave agno-grado-rbd-area: %d)", dup_rbd))
Verificación de escala (duplicados clave agno-grado-rbd-area: 0)
agno mediana_mate max_mate pct_sobre_1000 pct_bajo_100
2022 249.0 481.9 0.00% 0.00%
2023 256.7 472.9 0.00% 0.00%
2024 251.5 476.2 0.00% 3.19%
2025 259.2 483.2 0.00% 0.00%

Ambas correcciones se confirman: no hay duplicados y ya no existen puntajes > 1.000. Sin embargo, en 2024 persiste un ~3% de puntajes menores a 100 (imposibles en la escala SIMCE), residuo del problema de decimales que se corrige a continuación.

# Los valores < 100 en 2024 son órdenes de magnitud demasiado pequeños
# (ej.: 23.78 en vez de 237.8; 1.54 en vez de 154). Se reescalan multiplicando
# por 10 hasta entrar al rango plausible de la escala SIMCE (>= 100).
reescala <- function(x) {
  for (i in 1:2) x <- if_else(!is.na(x) & x < 100, x * 10, x)
  x
}

n_corr_mate <- sum(simce_alu$ptje_mate < 100, na.rm = TRUE)
n_corr_lect <- sum(simce_alu$ptje_lect < 100, na.rm = TRUE)

simce_alu <- simce_alu %>%
  mutate(ptje_mate = reescala(ptje_mate),
         ptje_lect = reescala(ptje_lect))

tibble(variable = c("ptje_mate", "ptje_lect"),
       registros_reescalados = comma(c(n_corr_mate, n_corr_lect))) %>%
  kable(caption = "Corrección residual aplicada (valores < 100 llevados a escala SIMCE)")
Corrección residual aplicada (valores < 100 llevados a escala SIMCE)
variable registros_reescalados
ptje_mate 20,309
ptje_lect 20,673

2.2 Cobertura por año, grado y área

bind_rows(
  ensayos   %>% count(agno, grado) %>% mutate(fuente = "Ensayos"),
  simce_rbd %>% count(agno, grado) %>% mutate(fuente = "SIMCE RBD"),
  simce_alu %>% count(agno, grado) %>% mutate(fuente = "SIMCE alumno")
) %>%
  unite(col, fuente, grado) %>%
  pivot_wider(names_from = col, values_from = n, values_fill = 0) %>%
  kable(caption = "Registros por año, fuente y grado")
Registros por año, fuente y grado
agno Ensayos_2m Ensayos_4b SIMCE RBD_2m SIMCE RBD_4b SIMCE RBD_6b SIMCE RBD_8b SIMCE alumno_2m SIMCE alumno_4b SIMCE alumno_6b SIMCE alumno_8b
2023 10617 16511 5980 14406 0 0 253128 249836 0 0
2024 37816 48865 5998 14368 14170 0 263828 263018 259916 0
2025 73216 78881 6002 14284 0 12050 268526 260968 0 269354
2022 0 0 5950 14418 0 0 246753 256743 0 0

Lectura: el SIMCE cubre 2022–2025 y los ensayos 2023–2025, con fuerte crecimiento del volumen de ensayos en 2025. El traslape 2023–2025 es la ventana para los análisis de consistencia y evolución conjunta.

3 Ensayos Santillana

3.1 Distribución general del porcentaje de logro

ensayos %>%
  ggplot(aes(porcentaje_logro)) +
  geom_histogram(binwidth = 5, fill = "#7570B3", color = "white") +
  scale_x_continuous(breaks = 10*0:15, limits = c(0, 150)) +
  geom_vline(xintercept = 100, linetype = "dashed", color = "red") +
  labs(title = "Distribución del porcentaje de logro (todas las evaluaciones)",
       x = "% de logro", y = "N° de registros")

ensayos %>%
  summarise(n = n(),
            media = mean(porcentaje_logro, na.rm = TRUE),
            mediana = median(porcentaje_logro, na.rm = TRUE),
            de = sd(porcentaje_logro, na.rm = TRUE),
            p10 = quantile(porcentaje_logro, .10, na.rm = TRUE),
            p90 = quantile(porcentaje_logro, .90, na.rm = TRUE),
            pct_cero = percent(mean(porcentaje_logro == 0, na.rm = TRUE), .1),
            n_sobre_100 = sum(porcentaje_logro > 100, na.rm = TRUE)) %>%
  mutate(across(where(is.numeric), ~round(.x, 2))) %>%
  kable(caption = "Estadísticos del % de logro")
Estadísticos del % de logro
n media mediana de p10 p90 pct_cero n_sobre_100
265906 56.81 60 22.24 25.71 85 1.1% 29

3.2 Por grado, área y año

ensayos %>%
  filter(porcentaje_logro <= 100) %>%
  ggplot(aes(x = factor(agno), y = porcentaje_logro, fill = area)) +
  geom_boxplot(outlier.alpha = .05) +
  facet_grid(grado~., labeller = labeller(grado = lab_grado)) +
  scale_fill_manual(values = pal_area) +
  labs(title = "% de logro por año, área y grado", x = "Año", y = "% de logro", fill = "Área")

ensayos %>%
  group_by(agno, grado, area) %>%
  summarise(media = round(mean(porcentaje_logro, na.rm = TRUE), 1),
            mediana = round(median(porcentaje_logro, na.rm = TRUE), 1),
            n = n(), .groups = "drop") %>%
  kable(caption = "Promedio y mediana del % de logro por año, grado y área")
Promedio y mediana del % de logro por año, grado y área
agno grado area media mediana n
2023 2m lenguaje 58.3 60.0 5469
2023 2m matematica 32.4 30.0 5148
2023 4b lenguaje 57.5 60.0 8471
2023 4b matematica 57.8 60.0 8040
2024 2m lenguaje 59.8 63.0 21892
2024 2m matematica 39.8 37.5 15924
2024 4b lenguaje 60.4 63.0 27737
2024 4b matematica 62.1 63.0 21128
2025 2m lenguaje 62.3 65.0 38824
2025 2m matematica 38.1 35.0 34392
2025 4b lenguaje 62.4 66.0 40564
2025 4b matematica 64.7 66.0 38317

Lectura: destaca el bajo logro de matemática en 2° medio (medias en torno a 32–40%), muy por debajo de lenguaje del mismo grado y de ambas áreas en 4° básico. Esto puede reflejar tanto menor dominio real como mayor dificultad relativa de los instrumentos de ese nivel; la comparación con SIMCE (sección de consistencia) ayuda a distinguirlo.

3.3 Progresión entre ensayos sucesivos (n_evaluacion)

ensayos %>%
  group_by(agno, grado, area, n_evaluacion) %>%
  summarise(media = mean(porcentaje_logro, na.rm = TRUE), n = n(), .groups = "drop") %>%
  ggplot(aes(x = n_evaluacion, y = media, color = area,
             linetype = factor(agno), group = interaction(agno, area))) +
  geom_line(linewidth = .8) + geom_point() +
  facet_wrap(~grado, labeller = labeller(grado = lab_grado)) +
  scale_color_manual(values = pal_area) +
  scale_x_discrete(breaks = 1:6) +
  labs(title = "Promedio del % de logro según número de evaluación",
       subtitle = "¿Mejoran los resultados entre aplicaciones sucesivas dentro del año?",
       x = "N° de evaluación en el año", y = "% de logro promedio",
       color = "Área", linetype = "Año")

Precaución interpretativa: los cambios entre aplicaciones mezclan aprendizaje, diferencias de dificultad entre instrumentos (apellido_evaluacion) y cambios de composición (colegios que solo rinden algunas aplicaciones). Para monitoreo fino conviene seguir al mismo id_usuario_curso entre aplicaciones.

3.4 Comparación entre tipo de evaluaciones

ensayos %>%
  mutate(evaluacion = paste0(tipo_evaluacion, ' - ', apellido_evaluacion)) %>% 
  ggplot(aes(y = evaluacion, x = porcentaje_logro)) +
  geom_line(linewidth = .8) + 
  geom_point() +
  facet_wrap(grado~area, scales = 'free_y') +
  geom_boxplot()

3.5 Comparación entre evaluaciones en general

ensayos %>%
  mutate(evaluacion = paste0(tipo_evaluacion, '-',n_evaluacion)) %>% 
  group_by(evaluacion, tipo_evaluacion, n_evaluacion, grado, area, agno) %>% 
  summarise(promedio = mean(porcentaje_logro, na.rm = TRUE),
            p25 = quantile(porcentaje_logro, probs = .25, na.rm = TRUE),
            p75 = quantile(porcentaje_logro, probs = .75, na.rm = TRUE),
            .groups = 'drop') %>%
  arrange(tipo_evaluacion, n_evaluacion) %>% 
  mutate(agno = factor(agno)) %>% 
  ggplot(aes(y = promedio, 
             color = agno,
             fill = agno,
             x = fct_rev(evaluacion),
             group = interaction(grado, area, agno))) +
  geom_line(linewidth = .8) + 
  geom_point() +
  geom_ribbon(aes(ymin = p25, ymax = p75), alpha = 0.2)+
  facet_wrap(grado~area, scales = 'free_x') +
  scale_y_continuous(limits = c(0, 100))+
  coord_flip()

4 SIMCE a nivel colegio (RBD)

Los valores 0 de promedio_simce se tratan como faltantes (la escala SIMCE parte alrededor de 100 puntos).

simce_rbd <- simce_rbd %>%
  mutate(promedio_valido = if_else(promedio_simce > 0, promedio_simce, NA_real_),
         dependencia = factor(cod_depe2, levels = 1:4,
                              labels = c("Municipal", "Part. subvencionado",
                                         "Part. pagado", "Serv. Local (SLEP)")),
         gse = factor(cod_grupo, levels = 1:5,
                      labels = c("Bajo", "Medio bajo", "Medio", "Medio alto", "Alto")))

4.1 Distribución del promedio SIMCE

simce_rbd %>%
  filter(!is.na(promedio_valido)) %>%
  ggplot(aes(promedio_valido, fill = area)) +
  geom_density(alpha = .5) +
  scale_fill_manual(values = pal_area) +
  facet_wrap(~grado, labeller = labeller(grado = lab_grado)) +
  labs(title = "Distribución del promedio SIMCE por grado y área (RBD)",
       x = "Promedio SIMCE", y = "Densidad", fill = "Área")

4.2 Tendencia por año

Se reporta el promedio ponderado por alumnos evaluados (nalu), que representa mejor al estudiante promedio que el promedio simple entre colegios.

simce_rbd %>%
  filter(!is.na(promedio_valido)) %>%
  group_by(agno, grado, area) %>%
  summarise(media_pond = weighted.mean(promedio_valido, nalu, na.rm = TRUE),
            .groups = "drop") %>%
  ggplot(aes(agno, media_pond, color = area, group = area)) +
  geom_line(linewidth = .9) + geom_point(size = 2) +
  facet_wrap(~grado, labeller = labeller(grado = lab_grado)) +
  scale_color_manual(values = pal_area) +
  labs(title = "Promedio SIMCE ponderado por alumnos, según año, grado y área",
       x = "Año", y = "Promedio SIMCE", color = "Área")

4.3 Brechas por dependencia y grupo socioeconómico

Los metadatos nuevos permiten dimensionar las brechas estructurales del sistema (etiquetas según codificación estándar SIMCE; verificar con el diccionario oficial de la Agencia de Calidad).

simce_rbd %>%
  filter(!is.na(promedio_valido), !is.na(gse)) %>%
  filter(grado %in% c('4b', '2m')) %>% 
  ggplot(aes(area, promedio_valido, fill = gse)) +
  geom_boxplot() +
  facet_grid(grado~.) +
  # scale_fill_manual() +
  labs(title = "Promedio SIMCE por grupo socioeconómico del colegio",
       x = "Grupo socioeconómico", y = "Promedio SIMCE", fill = "Área")

simce_rbd %>%
  filter(!is.na(promedio_valido), !is.na(dependencia)) %>%
  group_by(grado, area, dependencia) %>%
  summarise(media_pond = round(weighted.mean(promedio_valido, nalu, na.rm = TRUE), 1),
            n_colegios = n_distinct(rbd), .groups = "drop") %>%
  pivot_wider(names_from = dependencia, values_from = c(media_pond, n_colegios)) %>%
  kable(caption = "Promedio SIMCE ponderado por dependencia administrativa")
Promedio SIMCE ponderado por dependencia administrativa
grado area media_pond_Municipal media_pond_Part. subvencionado media_pond_Part. pagado media_pond_Serv. Local (SLEP) n_colegios_Municipal n_colegios_Part. subvencionado n_colegios_Part. pagado n_colegios_Serv. Local (SLEP)
2m lenguaje 236.1 248.3 284.2 233.2 757 1686 457 328
2m matematica 238.3 257.9 322.2 236.1 756 1686 457 328
4b lenguaje 264.3 273.2 302.7 263.9 3299 2888 494 1205
4b matematica 249.4 258.3 292.3 248.4 3297 2888 494 1204
6b lenguaje 239.4 249.7 281.0 236.8 2718 2723 476 559
6b matematica 231.2 244.9 291.0 228.1 2717 2726 478 557
8b lenguaje 227.8 238.7 274.3 224.1 1860 2546 476 1039
8b matematica 244.5 259.7 306.3 240.4 1861 2547 476 1042

5 SIMCE a nivel alumno

5.1 Distribuciones por grado, año y área

simce_alu %>%
  select(agno, grado, Matemática = ptje_mate, Lectura = ptje_lect) %>%
  pivot_longer(c(Matemática, Lectura), names_to = "area", values_to = "ptje") %>%
  filter(!is.na(ptje)) %>%
  ggplot(aes(ptje, fill = area)) +
  geom_density(alpha = .5) +
  facet_grid(grado ~ agno, labeller = labeller(grado = lab_grado)) +
  scale_fill_manual(values = c(Lectura = "#2C7FB8", `Matemática` = "#D95F02")) +
  labs(title = "Distribución de puntajes individuales por grado y año",
       x = "Puntaje SIMCE", y = "Densidad", fill = "Área")

simce_alu %>%
  group_by(agno, grado) %>%
  summarise(media_mate = round(mean(ptje_mate, na.rm = TRUE), 1),
            media_lect = round(mean(ptje_lect, na.rm = TRUE), 1),
            pct_na_mate = percent(mean(is.na(ptje_mate)), .1),
            pct_na_lect = percent(mean(is.na(ptje_lect)), .1),
            n = comma(n()), .groups = "drop") %>%
  kable(caption = "Promedios individuales y proporción de puntajes faltantes")
Promedios individuales y proporción de puntajes faltantes
agno grado media_mate media_lect pct_na_mate pct_na_lect n
2022 2m 251.7 243.0 23.6% 24.5% 246,753
2022 4b 250.4 267.1 17.9% 18.9% 256,743
2023 2m 256.9 248.0 21.1% 21.4% 253,128
2023 4b 259.0 272.0 16.6% 17.3% 249,836
2024 2m 259.3 249.7 22.7% 22.7% 263,828
2024 4b 264.4 278.0 17.2% 17.9% 263,018
2024 6b 244.8 249.2 17.5% 18.8% 259,916
2025 2m 263.0 250.7 25.1% 24.5% 268,526
2025 4b 261.8 276.2 18.6% 19.6% 260,968
2025 8b 258.5 237.9 19.2% 19.5% 269,354

5.2 Estándares de aprendizaje (eda)

etiquetas_eda <- c("Insuficiente", "Elemental", "Adecuado")

simce_alu %>%
  filter(!is.na(eda_mate)) %>%
  count(agno, grado, eda = factor(eda_mate, levels = 1:3, labels = etiquetas_eda)) %>%
  group_by(agno, grado) %>% mutate(prop = n / sum(n)) %>% ungroup() %>%
  ggplot(aes(factor(agno), prop, fill = eda)) +
  geom_col(position = "fill") +
  facet_wrap(~grado, labeller = labeller(grado = lab_grado)) +
  scale_y_continuous(labels = percent) +
  scale_fill_manual(values = c("#D7301F", "#FDB863", "#1A9850")) +
  labs(title = "Matemática: distribución de estándares de aprendizaje por año y grado",
       x = "Año", y = "Proporción de alumnos", fill = "Estándar")

5.3 Relación entre matemática y lectura

set.seed(1)
muestra <- simce_alu %>%
  filter(!is.na(ptje_mate), !is.na(ptje_lect)) %>%
  slice_sample(n = 50000)

r_ml <- cor(muestra$ptje_mate, muestra$ptje_lect)

ggplot(muestra, aes(ptje_lect, ptje_mate)) +
  geom_hex(bins = 60) +
  geom_smooth(method = "lm", color = "red", se = FALSE) +
  scale_fill_viridis_c() +
  labs(title = sprintf("Puntaje matemática vs. lectura (muestra 50.000; r = %.2f)", r_ml),
       x = "Lectura", y = "Matemática")

6 Consistencia entre fuentes

6.1 SIMCE alumno agregado a RBD vs. base SIMCE-RBD

agg_alu <- simce_alu %>%
  group_by(agno, grado, rbd) %>%
  summarise(matematica = mean(ptje_mate, na.rm = TRUE),
            lenguaje = mean(ptje_lect, na.rm = TRUE),
            n_alu_calc = n(), .groups = "drop") %>%
  pivot_longer(c(matematica, lenguaje), names_to = "area", values_to = "prom_alu") %>%
  filter(!is.nan(prom_alu))

comparacion <- simce_rbd %>%
  filter(!is.na(promedio_valido)) %>%
  select(agno, grado, rbd, area, promedio_valido, nalu) %>%
  inner_join(agg_alu, by = c("agno", "grado", "rbd", "area")) %>%
  mutate(dif = prom_alu - promedio_valido)

comparacion %>%
  group_by(agno, grado, area) %>%
  summarise(n_colegios = n(),
            correlacion = round(cor(prom_alu, promedio_valido), 3),
            dif_media = round(mean(dif), 2),
            dif_abs_mediana = round(median(abs(dif)), 2),
            pct_dif_mayor_10 = percent(mean(abs(dif) > 10), .1),
            .groups = "drop") %>%
  kable(caption = "Consistencia: promedio calculado desde alumnos vs. base RBD")
Consistencia: promedio calculado desde alumnos vs. base RBD
agno grado area n_colegios correlacion dif_media dif_abs_mediana pct_dif_mayor_10
2022 2m lenguaje 2967 0.998 0.02 0.27 0.3%
2022 2m matematica 2968 1.000 -0.03 0.27 0.3%
2022 4b lenguaje 6375 0.984 -0.07 0.28 3.5%
2022 4b matematica 6368 0.988 -0.02 0.28 2.8%
2023 2m lenguaje 2969 0.999 0.04 0.26 0.2%
2023 2m matematica 2969 1.000 0.03 0.27 0.1%
2023 4b lenguaje 6361 0.985 0.00 0.29 3.4%
2023 4b matematica 6355 0.989 -0.10 0.28 2.9%
2024 2m lenguaje 2992 0.991 0.56 0.26 2.3%
2024 2m matematica 2993 1.000 0.02 0.26 0.1%
2024 4b lenguaje 6450 0.987 0.12 0.27 3.0%
2024 4b matematica 6442 0.992 0.05 0.27 2.5%
2024 6b lenguaje 6324 0.988 -0.07 0.27 2.8%
2024 6b matematica 6325 0.993 -0.02 0.27 2.3%
2025 2m lenguaje 2997 0.994 0.33 0.27 1.6%
2025 2m matematica 2996 1.000 0.00 0.27 0.1%
2025 4b lenguaje 6407 0.984 0.04 0.28 3.3%
2025 4b matematica 6412 0.991 0.04 0.28 2.5%
2025 8b lenguaje 5879 0.992 0.10 0.28 1.6%
2025 8b matematica 5887 0.996 0.11 0.28 1.2%
comparacion %>%
  filter(n_alu_calc >= 10) %>%
  ggplot(aes(promedio_valido, prom_alu)) +
  geom_point(alpha = .15, size = .7) +
  geom_abline(color = "red", linetype = "dashed") +
  facet_grid(area ~ agno) +
  coord_equal() +
  labs(title = "Promedio por colegio: calculado desde alumnos vs. reportado en base RBD",
       subtitle = "Colegios con al menos 10 alumnos; la línea roja es la identidad",
       x = "Promedio SIMCE (base RBD)", y = "Promedio desde base alumnos")

comparacion %>%
  filter(abs(dif) > 10, n_alu_calc >= 10) %>%
  arrange(desc(abs(dif))) %>%
  select(agno, grado, rbd, area, n_alu_calc, nalu, prom_alu, promedio_valido, dif) %>%
  mutate(across(c(prom_alu, dif), ~round(.x, 1))) %>%
  head(20) %>%
  kable(caption = "Top 20 colegios con mayor discrepancia absoluta (>10 pts, n≥10)")
Top 20 colegios con mayor discrepancia absoluta (>10 pts, n≥10)
agno grado rbd area n_alu_calc nalu prom_alu promedio_valido dif
2024 2m 8380 lenguaje 19 14 259.7 196 63.7
2025 2m 14823 lenguaje 24 16 243.7 188 55.7
2025 8b 1577 lenguaje 23 3 301.3 250 51.3
2024 2m 1367 lenguaje 29 19 281.4 235 46.4
2022 4b 5794 matematica 11 3 194.9 240 -45.1
2025 2m 8926 lenguaje 217 99 296.5 253 43.5
2025 8b 557 lenguaje 30 21 271.3 230 41.3
2024 2m 1361 lenguaje 31 22 224.2 184 40.2
2024 2m 31084 lenguaje 36 23 237.2 198 39.2
2024 2m 11217 lenguaje 26 23 245.9 209 36.9
2024 2m 10604 matematica 36 3 275.5 239 36.5
2024 2m 10626 lenguaje 32 23 267.2 231 36.2
2025 4b 25677 lenguaje 13 4 200.9 237 -36.1
2024 2m 16604 lenguaje 33 24 305.9 270 35.9
2024 2m 3888 lenguaje 30 23 246.9 211 35.9
2024 2m 13590 lenguaje 38 25 245.3 210 35.3
2024 2m 20324 lenguaje 75 50 259.2 224 35.2
2022 4b 3085 lenguaje 10 4 219.1 253 -33.9
2024 2m 24448 lenguaje 42 27 224.5 192 32.5
2025 2m 19953 matematica 12 3 273.4 241 32.4

Lectura: con las bases corregidas la consistencia es alta (correlaciones ~0,97+ y diferencia mediana bajo 1 punto). Las discrepancias residuales se explican mayormente por diferencias entre nalu (alumnos considerados por la Agencia) y los alumnos con puntaje presentes en la base individual.

6.2 Ensayos vs. SIMCE del mismo año (nivel colegio)

agg_ens <- ensayos %>%
  filter(!is.na(rbd_revisado), porcentaje_logro <= 100) %>%
  mutate(rbd = as.integer(rbd_revisado)) %>%
  group_by(agno, grado, rbd, area) %>%
  summarise(logro_ensayo = mean(porcentaje_logro), n_reg = n(), .groups = "drop")

ens_simce <- simce_rbd %>%
  filter(!is.na(promedio_valido)) %>%
  select(agno, grado, rbd, area, promedio_valido, gse, dependencia) %>%
  inner_join(agg_ens, by = c("agno", "grado", "rbd", "area"))

ens_simce %>%
  group_by(agno, grado, area) %>%
  summarise(n_colegios = n(),
            correlacion = round(cor(logro_ensayo, promedio_valido), 3),
            .groups = "drop") %>%
  kable(caption = "Correlación entre % de logro promedio en ensayos y promedio SIMCE (mismo colegio-año)")
Correlación entre % de logro promedio en ensayos y promedio SIMCE (mismo colegio-año)
agno grado area n_colegios correlacion
2023 2m lenguaje 48 0.779
2023 2m matematica 41 0.493
2023 4b lenguaje 72 0.821
2023 4b matematica 72 0.761
2024 2m lenguaje 112 0.649
2024 2m matematica 97 0.697
2024 4b lenguaje 142 0.654
2024 4b matematica 135 0.798
2025 2m lenguaje 152 0.824
2025 2m matematica 143 0.660
2025 4b lenguaje 184 0.714
2025 4b matematica 177 0.764
ens_simce %>%
  filter(n_reg >= 20) %>%
  ggplot(aes(logro_ensayo, promedio_valido, color = area)) +
  geom_point(alpha = .25, size = .8) +
  geom_smooth(method = "lm", se = FALSE) +
  facet_grid(grado ~ agno, labeller = labeller(grado = lab_grado)) +
  scale_color_manual(values = pal_area) +
  labs(title = "Ensayos Santillana vs. SIMCE del mismo año (nivel colegio)",
       subtitle = "Colegios con al menos 20 registros de ensayo",
       x = "% de logro promedio en ensayos", y = "Promedio SIMCE", color = "Área")

Lectura: una correlación positiva moderada-alta respalda el uso de los ensayos como señal temprana del SIMCE. Correlaciones bajas en alguna celda año-grado-área sugieren emparejamiento de RBD deficiente, instrumentos poco alineados o pocas observaciones por colegio.

7 Evolución temporal: SIMCE vs. Ensayos

Como las escalas son distintas (puntos SIMCE vs. % de logro), la evolución conjunta se analiza de dos maneras complementarias.

7.1 Series estandarizadas (z-score respecto del primer año común)

Cada serie se expresa en desviaciones estándar respecto de su propio nivel y dispersión entre colegios en 2023 (primer año con ambas fuentes). Así, ambas curvas parten comparables y los movimientos se leen en unidades de “desviaciones estándar entre colegios”.

serie_simce <- simce_rbd %>%
  filter(!is.na(promedio_valido)) %>%
  group_by(grado, area) %>%
  mutate(mu0 = mean(promedio_valido[agno == 2023]),
         sd0 = sd(promedio_valido[agno == 2023])) %>%
  group_by(agno, grado, area) %>%
  summarise(z = mean((promedio_valido - mu0) / sd0), .groups = "drop") %>%
  mutate(fuente = "SIMCE")

serie_ens <- agg_ens %>%
  group_by(grado, area) %>%
  mutate(mu0 = mean(logro_ensayo[agno == 2023]),
         sd0 = sd(logro_ensayo[agno == 2023])) %>%
  group_by(agno, grado, area) %>%
  summarise(z = mean((logro_ensayo - mu0) / sd0), .groups = "drop") %>%
  mutate(fuente = "Ensayos")

bind_rows(serie_simce, serie_ens) %>%
  filter(agno >= 2023) %>%
  ggplot(aes(agno, z, color = fuente, group = fuente)) +
  geom_hline(yintercept = 0, color = "grey70") +
  geom_line(linewidth = .9) + geom_point(size = 2) +
  facet_grid(grado ~ area, labeller = labeller(grado = lab_grado)) +
  scale_color_manual(values = pal_fuente) +
  labs(title = "Evolución de SIMCE y Ensayos, estandarizados respecto de 2023",
       subtitle = "Promedio entre colegios, en desviaciones estándar (entre colegios) del año base",
       x = "Año", y = "Z-score (base 2023)", color = "Fuente")

7.2 Panel balanceado de colegios (control de composición)

Las series anteriores mezclan colegios distintos cada año (la muestra Santillana creció mucho en 2024–2025), por lo que parte del movimiento puede ser cambio de composición. Aquí se restringe a los colegios presentes en ambas fuentes en todos los años 2023–2025 para cada grado-área.

panel <- ens_simce %>%
  group_by(grado, area, rbd) %>%
  filter(all(2023:2025 %in% agno)) %>%
  ungroup()

panel %>%
  distinct(grado, area, rbd) %>%
  count(grado, area, name = "colegios_panel") %>%
  kable(caption = "Tamaño del panel balanceado 2023-2025 por grado y área")
Tamaño del panel balanceado 2023-2025 por grado y área
grado area colegios_panel
2m lenguaje 17
2m matematica 13
4b lenguaje 32
4b matematica 28
panel_z <- panel %>%
  group_by(grado, area) %>%
  mutate(z_simce = (promedio_valido - mean(promedio_valido[agno == 2023])) /
                    sd(promedio_valido[agno == 2023]),
         z_ens   = (logro_ensayo - mean(logro_ensayo[agno == 2023])) /
                    sd(logro_ensayo[agno == 2023])) %>%
  group_by(agno, grado, area) %>%
  summarise(SIMCE = mean(z_simce), Ensayos = mean(z_ens), .groups = "drop") %>%
  pivot_longer(c(SIMCE, Ensayos), names_to = "fuente", values_to = "z")

panel_z %>%
  ggplot(aes(agno, z, color = fuente, group = fuente)) +
  geom_hline(yintercept = 0, color = "grey70") +
  geom_line(linewidth = .9) + geom_point(size = 2) +
  facet_grid(grado ~ area, labeller = labeller(grado = lab_grado)) +
  scale_color_manual(values = pal_fuente) +
  labs(title = "Evolución en el panel balanceado de colegios (mismos colegios cada año)",
       subtitle = "Z-scores respecto de 2023; aísla el efecto composición",
       x = "Año", y = "Z-score (base 2023)", color = "Fuente")

7.3 ¿El cambio en ensayos anticipa el cambio en SIMCE?

Dentro del panel, se correlaciona el cambio anual por colegio en ambas medidas. Una correlación positiva indicaría que las variaciones de los ensayos capturan variaciones reales de desempeño y no solo ruido.

cambios <- panel %>%
  arrange(grado, area, rbd, agno) %>%
  group_by(grado, area, rbd) %>%
  mutate(d_simce = promedio_valido - lag(promedio_valido),
         d_ens   = logro_ensayo - lag(logro_ensayo)) %>%
  ungroup() %>%
  filter(!is.na(d_simce))

cambios %>%
  group_by(grado, area) %>%
  summarise(n_cambios = n(),
            correlacion_cambios = round(cor(d_ens, d_simce), 3),
            .groups = "drop") %>%
  kable(caption = "Correlación entre el cambio anual del % de logro en ensayos y el cambio del promedio SIMCE (mismo colegio)")
Correlación entre el cambio anual del % de logro en ensayos y el cambio del promedio SIMCE (mismo colegio)
grado area n_cambios correlacion_cambios
2m lenguaje 34 0.470
2m matematica 26 0.171
4b lenguaje 64 0.581
4b matematica 56 0.493
cambios %>%
  ggplot(aes(d_ens, d_simce)) +
  geom_point(alpha = .3, size = .8, color = "#7570B3") +
  geom_smooth(method = "lm", color = "red", se = TRUE) +
  geom_hline(yintercept = 0, color = "grey70") +
  geom_vline(xintercept = 0, color = "grey70") +
  facet_grid(grado ~ area, labeller = labeller(grado = lab_grado)) +
  labs(title = "Cambio anual por colegio: ensayos vs. SIMCE",
       x = "Δ % de logro en ensayos", y = "Δ promedio SIMCE")

Lectura: las correlaciones de niveles entre colegios suelen ser altas, pero las de cambios son típicamente mucho menores (ambas medidas tienen error de medición y los cambios anuales son pequeños relativos a ese error). Si la correlación de cambios es cercana a 0, los ensayos sirven para ordenar colegios pero no necesariamente para detectar mejoras año a año de un mismo colegio.

8 Posibles errores y problemas de calidad detectados

tribble(
  ~fuente, ~problema, ~magnitud, ~estado,
  "SIMCE alumno", "Escala x100 (2024-2025)", "—", "Corregido en la fuente ✔",
  "SIMCE RBD", "Duplicados 2m-2024", "—", "Corregido en la fuente ✔",
  "SIMCE alumno", "Residuo de decimales: puntajes < 100 en 2024",
    comma(n_corr_mate + n_corr_lect), "Reescalado en este reporte (x10/x100)",
  "SIMCE RBD", "Promedios = 0 (tratados como faltantes)",
    comma(sum(simce_rbd$promedio_simce == 0, na.rm = TRUE)), "Excluidos del análisis",
  "SIMCE RBD", "Promedios faltantes (NA)",
    comma(sum(is.na(simce_rbd$promedio_simce))), "Excluidos del análisis",
  "SIMCE alumno", "Puntaje matemática faltante",
    percent(mean(is.na(simce_alu$ptje_mate)), .1), "Excluidos por variable",
  "SIMCE alumno", "Puntaje lectura faltante",
    percent(mean(is.na(simce_alu$ptje_lect)), .1), "Excluidos por variable",
  "Ensayos", "Porcentaje de logro > 100",
    comma(sum(ensayos$porcentaje_logro > 100, na.rm = TRUE)), "Excluidos de cruces con SIMCE",
  "Ensayos", "RBD faltante tras revisión (rbd_revisado)",
    comma(sum(is.na(ensayos$rbd_revisado))), "No cruzables con SIMCE",
  "Ensayos", "Nombres de alumnos en texto plano (columna nombre)",
    "toda la base", "Riesgo de privacidad: anonimizar"
) %>%
  kable(caption = "Resumen de problemas de calidad",
        col.names = c("Fuente", "Problema", "Magnitud", "Estado"))
Resumen de problemas de calidad
Fuente Problema Magnitud Estado
SIMCE alumno Escala x100 (2024-2025) Corregido en la fuente ✔
SIMCE RBD Duplicados 2m-2024 Corregido en la fuente ✔
SIMCE alumno Residuo de decimales: puntajes < 100 en 2024 40,982 Reescalado en este reporte (x10/x100)
SIMCE RBD Promedios = 0 (tratados como faltantes) 1,011 Excluidos del análisis
SIMCE RBD Promedios faltantes (NA) 5,434 Excluidos del análisis
SIMCE alumno Puntaje matemática faltante 20.0% Excluidos por variable
SIMCE alumno Puntaje lectura faltante 20.5% Excluidos por variable
Ensayos Porcentaje de logro > 100 29 Excluidos de cruces con SIMCE
Ensayos RBD faltante tras revisión (rbd_revisado) 11,984 No cruzables con SIMCE
Ensayos Nombres de alumnos en texto plano (columna nombre) toda la base Riesgo de privacidad: anonimizar

Notas:

  • El residuo de decimales (~40.000 registros de 2024 con puntajes como 23,78 o 1,54 en vez de 237,8 o 154) proviene del mismo problema de separadores ya corregido: valores con distinta cantidad de decimales quedaron divididos por 10 o por 100. Conviene corregirlo también en el origen.
  • La base de ensayos ahora incluye nombres de alumnos (nombre) y de colegios en texto plano. Para compartir o publicar resultados se recomienda eliminar o seudonimizar esas columnas.

9 Conclusiones

  1. Calidad: las dos correcciones de la fuente se verifican (sin duplicados, escala correcta), quedando solo un residuo menor de decimales en 2024 que este reporte corrige y que conviene arreglar en el origen.
  2. Panorama SIMCE: distribuciones en rango esperado, con la brecha esperable por grupo socioeconómico y dependencia; matemática de 2° medio es consistentemente el área más débil, coherente con el bajo % de logro de los ensayos de ese grado.
  3. Consistencia entre fuentes: el agregado por colegio desde la base de alumnos reproduce casi exactamente la base RBD (correlaciones ~0,97+, diferencia mediana < 1 punto), validando el uso conjunto.
  4. Evolución temporal: las series estandarizadas y el panel balanceado permiten comparar la trayectoria de ensayos y SIMCE en unidades comunes; el análisis de cambios por colegio indica en qué medida los ensayos detectan mejoras reales año a año además de ordenar colegios.
  5. Siguientes pasos sugeridos: equiparación formal de escalas ensayo→SIMCE (equipercentile linking), seguimiento longitudinal por mrun, ajuste por dificultad de instrumento (apellido_evaluacion), y modelos jerárquicos (alumno-curso-colegio) controlando GSE y dependencia para estimar efectos colegio robustos.