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):
consolidado_ensayo_simce.parquet): resultados a nivel de
alumno-evaluación (porcentaje de logro, 0–100).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).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).
# 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")
| fuente | filas | columnas |
|---|---|---|
| Ensayos Santillana | 265,906 | 17 |
| SIMCE por RBD | 107,626 | 14 |
| SIMCE por alumno | 2,592,070 | 13 |
# 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))
| 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)")
| variable | registros_reescalados |
|---|---|
| ptje_mate | 20,309 |
| ptje_lect | 20,673 |
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")
| 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.
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")
| n | media | mediana | de | p10 | p90 | pct_cero | n_sobre_100 |
|---|---|---|---|---|---|---|---|
| 265906 | 56.81 | 60 | 22.24 | 25.71 | 85 | 1.1% | 29 |
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")
| 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.
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.
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()
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()
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")))
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")
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")
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")
| 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 |
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")
| 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 |
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")
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")
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")
| 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)")
| 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.
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)")
| 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.
Como las escalas son distintas (puntos SIMCE vs. % de logro), la evolución conjunta se analiza de dos maneras complementarias.
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")
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")
| 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")
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)")
| 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.
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"))
| 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:
nombre) y de colegios en texto plano. Para compartir o
publicar resultados se recomienda eliminar o seudonimizar esas
columnas.mrun, ajuste por dificultad de instrumento
(apellido_evaluacion), y modelos jerárquicos
(alumno-curso-colegio) controlando GSE y dependencia para estimar
efectos colegio robustos.