Análisis Estadístico de los resultados del examen de admisión a licenciatura de la UNAM 2026

El examen de admisión a licenciatura de la UNAM fue realizado en línea por primera vez en su historia; cuando se publicaron los resultados, las personas en internet comenzaron a notar que la distribución de los aciertos fue anormal para varias carreras, muchos de los aspirantes habían hecho trampa para poder ingresar.

En este trabajo se hará una comparación de los resultados de los años anteriores con los del concurso de selección de este año 2026. Los datos fueron recopilados de un dataset de libre acceso en GitHub (Karen Arlet Castrillo Cruz. (2026). Resultados UNAM — Datos de admisión a licenciatura (2021–2026).

En este caso, solo se usará el archivo csv con los siguientes datos:

Tabla1. Tomada directamente de: Karen Arlet Castrillo Cruz. (2026). Resultados UNAM — Datos de admisión a licenciatura (2021–2026). https://github.com/agn3si/ResultadosUNAM—data
Columna Tipo Descripción
folio entero Folio del aspirante (identificador anónimo, no es información personal)
aciertos entero / NA Número de respuestas correctas en el examen. Nulo si el aspirante no presentó
acreditado S / N /C / NA S = seleccionado, N = no seleccionado, C = cancelado. Nulo cuando no aplica
año entero Año del proceso de admisión (2021–2026)
area entero (1-4) Área de conocimiento según clasificación de la DGAE
carrera texto Carrera solicitada
plantel texto Plantel/facultad solicitada

Overview de los datos

  • La base de datos cuenta con más de 1 millón de registros desde el año 2021 hasta el 2026

  • Hay 116 carreras ofertadas y se imparten en 54 planteles

  • La carrera con mayor cantidad de registros es la de Médico Cirujano

Análisis de datos

# cargar librerias
library("plotly")
library("dplyr")
library("tidyr")

# cargar base de datos
u <- read.csv("aciertos_unam_2021_2026.csv")

# Revisar la estructura de datos

str(u)
## 'data.frame':    1027716 obs. of  7 variables:
##  $ folio     : int  1 30 56 133 148 151 167 208 283 326 ...
##  $ aciertos  : num  71 93 49 90 62 51 111 85 NA 106 ...
##  $ acreditado: chr  "" "" "" "" ...
##  $ año       : int  2021 2021 2021 2021 2021 2021 2021 2021 2021 2021 ...
##  $ area      : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ carrera   : chr  "ACTUARIA" "ACTUARIA" "ACTUARIA" "ACTUARIA" ...
##  $ plantel   : chr  "FACULTAD DE CIENCIAS" "FACULTAD DE CIENCIAS" "FACULTAD DE CIENCIAS" "FACULTAD DE CIENCIAS" ...
# eliminar NAs
unam <- na.omit(u)

Ya que cargamos los datos y eliminamos los NAs, vamos a hacer el cálculo de la estadística en general.

# Vemos el resumen de los aciertos
summary(unam$aciertos)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.0    42.0    54.0    58.3    71.0   120.0
desv_st <- sd(unam$aciertos)
print(paste("Desviación estándar global:", round(desv_st, 2)))
## [1] "Desviación estándar global: 20.97"

Ahora, vamos a ver la distribución de los aciertos con histogramas

# Histograma

plot_ly(
  type = "histogram",
  x = unam$aciertos,
  marker = list(color = "#6E8B3D")
) %>%
  layout(
    title = "Distribución General de Aciertos (2021-2026)",
    xaxis = list(title = "Aciertos"),
    yaxis = list(title = "Frecuencia")
  )

En esta gráfica observamos la distribución de los datos del año 2021-2026. Ahora presento una comparativa de los años previos vs 2026.

Comparativa de años previos vs 2026

En este caso, vamos a separar los periodos y a graficar en boxplots para poder ver la comparación entre cada año:

unam <- unam %>%
  mutate(periodo = ifelse(año == 2026, "2026 (Sospecha?)", "2021-2025"))

# Graficamos el Boxplot para evidenciar el salto en los puntajes
plot_ly(
  data = unam,
  type = "box",
  y = ~aciertos,
  color = ~periodo,
  colors = c("#A2CD5A", "#FFB90F")
) %>%
  layout(
    title = "Anomalía de Puntajes: 2026 vs Años Previos",
    xaxis = list(title = "Periodo"),
    yaxis = list(title = "Aciertos")
  )

Podemos observar que los puntajes se dispararon, en años previos la mediana se mantuvo al rededor de los 52 aciertos, para el año 2026,la mediana subió a 71.

# Calcular cuartiles y percentiles altos por año
percentiles_por_año <- unam %>%
  group_by(año) %>%
  summarise(
    Mediana = median(aciertos),
    Top_25_Porciento = quantile(aciertos, 0.75),
    Top_10_Porciento = quantile(aciertos, 0.90)
  )

print(percentiles_por_año)
## # A tibble: 6 × 4
##     año Mediana Top_25_Porciento Top_10_Porciento
##   <int>   <dbl>            <dbl>            <dbl>
## 1  2021      52               67               84
## 2  2022      51               66               82
## 3  2023      52               68               84
## 4  2024      52               68               86
## 5  2025      52               68               86
## 6  2026      71               93              105
  • Se observa que de 2021-2025 la mediana se quedó entre 51 y 52 aciertos, la mitad de los aspirantes sacaban menos de 52 aciertos

  • Además, entre 2021-2025 el top 10% de los mejores aspirantes lograban sacar de 84-86 aciertos

  • En 2026 la mediana subió a 71 aciertos, el top10% de los aspirantes alcanzó los 105 aciertos

Carreras más solicitadas

¿Qué carreras son las que tienen más solicitudes? Quiero investigar si hay una correlación entre las carreras más solicitadas y los puntajes, en este caso, buscaremos si hay un incremento en el número de aciertos en esas carreras en comparación con los años anteriores.

top_carreras <- unam %>%
  count(carrera, sort = TRUE) %>%
  head(5)

print("Las 5 carreras más solicitadas:")
## [1] "Las 5 carreras más solicitadas:"
print(top_carreras)
##           carrera      n
## 1 MEDICO CIRUJANO 134189
## 2         DERECHO  63152
## 3      PSICOLOGIA  53144
## 4    ARQUITECTURA  44345
## 5  ADMINISTRACION  44274
plot_ly(
  x = top_carreras$carrera,
  y = top_carreras$n,
  type = "bar",
  marker = list(color = "#EEA2AD")
) %>%
  layout(
    title = "Top 5 Carreras con Mayor Demanda",
    xaxis = list(title = "Carrera"),
    yaxis = list(title = "Número de Aspirantes")
  )

Vamos a enfocarnos en las tres carreras con mayor volúmen histórico: Médico Cirujano, Derecho y Psicología.

# Filtrar las 3 carreras más solicitadas
carreras_top3 <- c("MEDICO CIRUJANO", "DERECHO", "PSICOLOGIA")

datos_top3 <- unam %>%
  filter(carrera %in% carreras_top3)

# Resumen de promedios por año para estas 3 carreras
resumen_top3 <- datos_top3 %>%
  group_by(carrera, año) %>%
  summarise(promedio = round(mean(aciertos), 1), .groups = 'drop') %>%
  pivot_wider(names_from = año, values_from = promedio)

print(resumen_top3, width = Inf)
## # A tibble: 3 × 7
##   carrera         `2021` `2022` `2023` `2024` `2025` `2026`
##   <chr>            <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1 DERECHO           53.4   52.3   53.1   54     54     70.8
## 2 MEDICO CIRUJANO   59.7   58.1   61     60     60.9   78.1
## 3 PSICOLOGIA        52.1   51.8   54.3   52.8   52.9   65.9

Se observa lo siguiente:

  • Médico cirujano: Anteriormente el promedio de aciertos rondaba los 60 aciertos. En 2026, el promedio se disparó a 78 aciertos

  • Derecho: La media histórica era de 53 aciertos, en 2026 saltó a 71

  • Psicología: Su promedio era de 52 aciertos y en 2026 subió a 65 aciertos

Cambios a lo largo del tiempo

# Pre-calcular las frecuencias
datos_animacion <- unam %>%
  # Creamos los bloques de aciertos (0-5, 5-10, etc.)
  mutate(grupo_aciertos = cut(aciertos, breaks = seq(0, 125, by = 5), right = FALSE)) %>%
  group_by(año, grupo_aciertos) %>%
  summarise(frecuencia = n(), .groups = 'drop') %>%
  # Sacamos el numero inicial del bloque para ponerlo en el eje X
  mutate(aciertos_eje_x = as.numeric(sub("\\[([0-9]+),.*", "\\1", grupo_aciertos))) %>%
  # Limpiamos los NA que puedan salir por el corte
  drop_na()

# 2.animación con "bar"

plot_ly(
  data = datos_animacion,
  x = ~aciertos_eje_x,
  y = ~frecuencia,
  frame = ~año,
  type = "bar",
  marker = list(color = "#6E8B3D", line = list(color = "white", width = 0.5)),
  width = 0.8
) %>%
  layout(
    title = "Evolución Histórica de Aciertos (2021-2026)",
    xaxis = list(
      title = "Aciertos", 
      range = c(0, 120),
      dtick = 10
    ),
    yaxis = list(
      title = "Frecuencia de Aspirantes",
      range = c(0, max(datos_animacion$frecuencia) + 2000) # Ajuste automático de altura
    )
  ) %>%
  animation_opts(
    frame = 1500,       # Duración de cada año en milisegundos
    transition = 800,   # Suavidad del movimiento de las barras
    easing = "linear",
    redraw = FALSE
  ) %>%
  animation_slider(
    currentvalue = list(prefix = "Año Evaluado: ", font = list(color = "#CD3700"))
  )

Planteles más solicitados

# Tabla de frecuencias para los planteles 

top_planteles <- unam %>%
  count(plantel, sort = TRUE) %>%
  head(10)

print(top_planteles)
##                                    plantel     n
## 1                             FES ZARAGOZA 96039
## 2                     FACULTAD DE MEDICINA 78823
## 3                             FES IZTACALA 75888
## 4                               FES ARAGÓN 73470
## 5                              FES ACATLÁN 53195
## 6                   FACULTAD DE INGENIERÍA 49338
## 7  FACULTAD DE CONTADURÍA Y ADMINISTRACIÓN 42420
## 8                           FES CUAUTITLÁN 41543
## 9                      FACULTAD DE DERECHO 32670
## 10                    FACULTAD DE CIENCIAS 29866

Área más demandada

La UNAM divide las carreras en 4 áreas:

  • Área 1 (Ciencias Físico-Matemáticas)

  • Área 2 (Biológicas y de la Salud)

  • Área 3 (Ciencias Sociales)

  • Área 4 (Humanidades y de las Artes)

# Calcular frecuencias por área
demanda_area <- unam %>%
  count(area) %>%
  mutate(area_nombre = paste("Área", area))

# Gráfico de pastel interactivo con Plotly
plot_ly(
  data = demanda_area,
  type = "pie",
  labels = ~area_nombre,
  values = ~n,
  hole = 0.4 # Esto lo hace un gráfico de dona (opcional, se ve muy bien)
) %>%
  layout(title = "Distribución de Aspirantes por Área de Conocimiento")

¿En la ENES Juriquilla?

Filtramos para analizar únicamente el plantel de la ENES Juriquilla

datos_juriquilla <- unam %>%
  filter(grepl("JURIQUILLA", plantel, ignore.case = TRUE))

demanda_juri <- datos_juriquilla %>%
  count(carrera, sort = TRUE)

print("Demanda por carrera en ENES Juriquilla:")
## [1] "Demanda por carrera en ENES Juriquilla:"
print(demanda_juri)
##                             carrera   n
## 1             CIENCIAS DE LA TIERRA 282
## 2                ORTESIS Y PROTESIS 215
## 3                        PSICOLOGIA 196
## 4                        TECNOLOGIA 146
## 5         INGENIERIA EN COMPUTACION 112
## 6    MATEMATICAS PARA EL DESARROLLO  86
## 7 INGENIERIA EN ENERGIAS RENOVABLES  66
# Tabla del promedio de aciertos por año en cada carrera

resumen_juri <- datos_juriquilla %>%
  group_by(carrera, año) %>%
  summarise(prom_aciertos = round(mean(aciertos), 1), .groups = 'drop') %>%
  pivot_wider(names_from = año, values_from = prom_aciertos)

print("Evolución de promedios de aciertos en Juriquilla:")
## [1] "Evolución de promedios de aciertos en Juriquilla:"
print(resumen_juri, width = Inf)
## # A tibble: 7 × 6
##   carrera                           `2021` `2022` `2023` `2025` `2026`
##   <chr>                              <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1 CIENCIAS DE LA TIERRA               70.6   62.9     64   61.8   72  
## 2 INGENIERIA EN COMPUTACION           NA     NA       NA   NA     74.4
## 3 INGENIERIA EN ENERGIAS RENOVABLES   NA     NA       NA   NA     76.6
## 4 MATEMATICAS PARA EL DESARROLLO      NA     NA       NA   73.9   83.8
## 5 ORTESIS Y PROTESIS                  NA     NA       NA   55.4   72.8
## 6 PSICOLOGIA                          NA     NA       NA   NA     68.8
## 7 TECNOLOGIA                          NA     NA       NA   64.4   76.2