Previsão de Matrículas UFPE em 2027

Metodologia

Este relatório apresenta a modelagem e previsão do número de matrículas na UFPE para os seguintes níveis:

  • Graduação presencial,
  • Graduação EAD,
  • Mestrado
  • Doutorado

Foram utilizadas abordagens como ARIMA com drift e regressão linear para séries temporais anuais (ou semestrais, no caso da graduação), com base em dados de 2016 a 2025.

OBS.: Os dados adicionados nas séries, relativos ao semestre 2025.2, foram os mesmos apresentados ao modaloc 2026, ou seja, foram extraídos do SIGAA

Graduação Presencial

Para a graduação presencial, utilizamos os dados do Censo da Educação Superior entre 2016 e 2024. Para o ano de 2025, incluímos dados do SIGAA. Como os dados são semestrais, temos 20 observações.

Primeiramente vamos plotar o gráfico da série:

# Previsoes de quantitativos de alunos UFPE 2027 graduacao presencial

library(readxl)
library(forecast)
library(tseries)
library(dplyr)
library(magrittr)
library(reactable)

# Graduação ---------------------------------------------------------------

# abrindo os dados

graduacao_discentes <- read_excel("dados/graduacao_discentes_COD.xlsx", 
                                  sheet = "graduacao_matriculados")



# graduacao presencial:

graduacao_presencial_2025 = tibble(ANO=c("2025", "2025"), 
                                   PERIODO_REFERENCIA = c("1", "2"), 
                                   Matriculados = c(28670, 28532))

graduacao_discentes %>% select(ANO:Matriculados) %>% 
  filter(MODALIDADE_ENSINO == "Presencial") %>% 
  group_by(ANO, PERIODO_REFERENCIA) %>% 
  summarise(Matriculados = sum(Matriculados)) %>% 
  bind_rows(graduacao_presencial_2025) %>% ungroup %>% 
  select(Matriculados) -> graduacao_presencial


graduacao_presencial %<>% ts(start =2016, frequency = 2) 

# plot
autoplot(graduacao_presencial)

Pelo gráfico da função de autocorrelação, vemos que a série não é estacionária. São necessárias duas diferenciações para que a série se torne estacionária:

ggAcf(graduacao_presencial)

autoplot(diff(graduacao_presencial))

ggAcf(diff(graduacao_presencial))

autoplot(diff(graduacao_presencial, 2))

ggAcf(diff(graduacao_presencial, 2))

# estacionaria: o valor d=2 no autoarima

Agora, vamos utilizar a função auto.arima para modelar os dados e obter a previsão para os dois semestres de 2027. Para obter a previsão do ano de 2027, vamos computar a média dos valores previstos para 2027.1 e 2027.2.

modelo_graduacao_presencial <- auto.arima(graduacao_presencial, 
                                          stepwise = FALSE, 
                                          approximation = FALSE)
summary(modelo_graduacao_presencial)
## Series: graduacao_presencial 
## ARIMA(1,1,0) 
## 
## Coefficients:
##           ar1
##       -0.5850
## s.e.   0.1776
## 
## sigma^2 = 342394:  log likelihood = -147.72
## AIC=299.44   AICc=300.19   BIC=301.33
## 
## Training set error measures:
##                     ME     RMSE      MAE        MPE     MAPE      MASE
## Training set -184.6912 555.1166 411.0543 -0.6474034 1.428275 0.8364206
##                    ACF1
## Training set 0.03747704
# checando os residuos do modelo:
# Conclusão: os resíduos não têm autocorrelação significativa
checkresiduals(modelo_graduacao_presencial)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(1,1,0)
## Q* = 1.4602, df = 3, p-value = 0.6915
## 
## Model df: 1.   Total lags used: 4
# Previsoes
previsao <- forecast(modelo_graduacao_presencial, h = 6)
#autoplot(previsao)

# Valores previstos para 2027.1 e 2027.2 (segundo e terceiro período futuro)
valores_2027 <- previsao$mean[3:4]  

Assim, obtemos o valor previsto para as matrícula da graduação presencial em 2027:

# Calculando a média
media_2027 <- mean(valores_2027)
print(ceiling(media_2027))
## [1] 28586

Graduação EaD

Seguindo a mesma metodologia, obtemos a previsão para o ano de 2027 para a graduação a distância.

Observação: no caso da graduação EAD, incluímos os dados de 2025, apesar dos números serem muito divergentes em relação ao histórico.

# Previsoes de quantitativos de alunos UFPE 2026 graduacao EAD

library(readxl)
library(forecast)
library(tseries)
library(dplyr)
library(magrittr)
library(ggplot2)

setwd("G:/Meu Drive/workspace/previsao_PLOA_2027/")

# Graduação ---------------------------------------------------------------

# abrindo os dados

graduacao_discentes <- read_excel("dados/graduacao_discentes_COD.xlsx", 
                                  sheet = "graduacao_matriculados")



# graduacao EAD:

graduacao_EAD_2025 = tibble(ANO=c("2025", "2025"), 
                            PERIODO_REFERENCIA = c("1", "2"),
                                   Matriculados = c(1835, 1362))

graduacao_discentes %>% select(ANO:Matriculados) %>% 
  filter(MODALIDADE_ENSINO == "EaD") %>% 
  group_by(ANO, PERIODO_REFERENCIA) %>% 
  summarise(Matriculados = sum(Matriculados)) %>% 
  bind_rows(graduacao_EAD_2025) %>%
  ungroup %>% 
  select(Matriculados) -> graduacao_EAD

graduacao_EAD %<>% ts(start =2016, frequency = 2)

# visualizacao
# autoplot(graduacao_EAD) + 
#   ggtitle("Matrículas em cursos EAD - UFPE") +
#   xlab("Ano") + ylab("Número de Matriculados")
# 
# # analise de estacionariedade
# autoplot(diff(graduacao_EAD))
# ggAcf(diff(graduacao_EAD))
# 
# # Teste de Dickey-Fuller aumentado (ADF)
# # a serie nao eh estacionaria, vamos tentar uma diferenciacao
# adf.test(graduacao_EAD)
# 
# graduacao_EAD_diff1 <- diff(graduacao_EAD)
# autoplot(graduacao_EAD_diff1)
# ggAcf(graduacao_EAD_diff1)
# adf.test(graduacao_EAD_diff1)


# Modelagem ARIMA
modelo_ead <- auto.arima(graduacao_EAD, stepwise = FALSE, approximation = FALSE)
summary(modelo_ead)
## Series: graduacao_EAD 
## ARIMA(0,1,1) 
## 
## Coefficients:
##           ma1
##       -0.6214
## s.e.   0.1781
## 
## sigma^2 = 142244:  log likelihood = -139.41
## AIC=282.82   AICc=283.57   BIC=284.71
## 
## Training set error measures:
##                    ME    RMSE      MAE      MPE     MAPE      MASE       ACF1
## Training set 105.6357 357.798 236.7875 1.027168 25.47985 0.5839397 -0.0916191
# validacao do modelo
checkresiduals(modelo_ead)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,1,1)
## Q* = 3.6585, df = 3, p-value = 0.3008
## 
## Model df: 1.   Total lags used: 4
previsao_ead <- forecast(modelo_ead, h = 6)
autoplot(previsao_ead)

# Seleciona os valores de 2027.1 e 2027.2
valores_2027 <- previsao_ead$mean[3:4]
media_ead_2027 <- mean(valores_2027)

print(valores_2027)
## [1] 1316.567 1316.567
print(media_ead_2027)
## [1] 1316.567

Por que a previsão ARIMA está constante?

O modelo ajustado foi um ARIMA(0,1,1) — um modelo de diferença com média móvel simples, sem termos autoregressivos, e isso tem implicações:

  • Esse tipo de modelo projeta uma tendência “neutra”, assumindo que as variações futuras serão semelhantes à média dos erros passados.

  • Como o modelo não tem componente autoregressivo (AR) nem tendência explícita (drift), ele não gera trajetória crescente ou decrescente.

Resultado: após o último valor da série, ele mantém a previsão constante, com bandas de incerteza que aumentam ao longo do horizonte.

Alternativamente, ajustamos um modelo ARIMA com drift:

modelo_drift <- Arima(graduacao_EAD, order = c(0,1,1), include.drift = TRUE)
summary(modelo_drift)
## Series: graduacao_EAD 
## ARIMA(0,1,1) with drift 
## 
## Coefficients:
##          ma1    drift
##       -1.000  42.4934
## s.e.   0.229  12.1913
## 
## sigma^2 = 110426:  log likelihood = -137.72
## AIC=281.43   AICc=283.03   BIC=284.27
## 
## Training set error measures:
##                     ME     RMSE     MAE       MPE     MAPE      MASE       ACF1
## Training set -25.33592 306.3694 246.772 -16.66787 32.68891 0.6085623 0.06561323
previsao_drift <- forecast(modelo_drift, h = 6)
autoplot(previsao_drift)

valores_2027_drift <- previsao_drift$mean[3:4]
media_2027_drift <- mean(valores_2027_drift)

print(ceiling(media_2027_drift))
## [1] 1387

Optamos por utilizar o valor previsto pelo modelo do auto.arima, isto é \(1317\).

Mestrado

Para o mestrado, temos observações anuais de 2016 até 2025. No momento da escrita deste relatório (março de 2026) ainda não dispomos do número de alunos de mestrado e doutorado em 2026. Portanto, vamos prever o valor de 2027 a partir da série que vai até 2025.

Como são somente 10 observações, vamos ajustar um modelo de regressão linear simples para prever o valor para 2027. Optamos pelo modelo de regressão pelos seguintes motivos:

  • Captura tendência crescente de forma direta.
  • Menos parâmetros do que ARIMA.
  • Funciona bem para séries pequenas com padrão linear.
# Dados -------------------------------------------------------------------

stricto_sensu <- read_excel("dados/Dados do Anuário.xlsx", 
                            sheet = "Pós-Graduação Stricto Sensu", 
                            col_types = c("numeric", "text", "text", 
                                          "text", "text", "skip", "numeric", 
                                          "skip", "skip"))


mestrado_2025 = tibble(Ano=2025, Matriculados = 4914)


stricto_sensu %>% filter(Nível %in% c("Mestrado Acadêmico",
                                      "Mestrado Profissional")) %>% 
  group_by(Ano) %>% 
  summarise(Matriculados = sum(Matriculado)) %>% 
  bind_rows(mestrado_2025) -> mestrado

# Dados originais
anos <- 2016:2025
matriculados <- c(4609, 4541, 4745, 4804, 4818, 4999, 5278, 5297, 5370, 4914)

# Ajuste da regressão linear
modelo_lm <- lm(matriculados ~ anos)

# Criar novo conjunto de dados com os anos que queremos prever
novos_anos <- data.frame(anos = c(2026, 2027))

# Gerar previsões apenas para 2025 a 2027
previsoes <- predict(modelo_lm, newdata = novos_anos)

# Ver resultados
# print(previsoes)

# comparando com o ARIMA com drift:

# ts_mestrado <- ts(matriculados, start = 2016, frequency = 1)
# modelo_drift <- Arima(ts_mestrado, order = c(0,1,1), include.drift = TRUE)
# previsao_mestrado <- forecast(modelo_drift, h = 2) 
# 

previsao_mestrado_LINEAR_MODEL = previsoes[2]
# previsao_mestrado_ARIMA_DRIFT = previsao_mestrado$mean[2]


ceiling(previsao_mestrado_LINEAR_MODEL)
##    2 
## 5447
#ceiling(previsao_mestrado_ARIMA_DRIFT)

Obtemos o valor previsto de \(5447\) alunos no mestrado para o ano de 2027.

Doutorado

Para o doutorado, novamente temos 10 observações. Por ser uma série muito “curta”, vamos utilizar novamente a regressão simples como método de predição.

doutorado_2025 = tibble(Ano=2025, Matriculados = 3363)


stricto_sensu %>% filter(Nível %in% c("Doutorado Acadêmico",
                                      "Doutorado Profissional")) %>% 
  group_by(Ano) %>% 
  summarise(Matriculados = sum(Matriculado)) %>% 
  bind_rows(doutorado_2025) -> doutorado


# Dados
anos <- 2016:2025
matriculados <- c(3824, 3914, 3916, 3932, 4006, 4152, 4351, 4308, 4296, 3363)

# Ajuste do modelo linear
modelo_lm_doutorado <- lm(matriculados ~ anos)
summary(modelo_lm_doutorado)
## 
## Call:
## lm(formula = matriculados ~ anos)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -694.69  -60.45  -23.32  222.33  327.64 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)
## (Intercept) -19113.22   69167.98  -0.276    0.789
## anos            11.44      34.23   0.334    0.747
## 
## Residual standard error: 310.9 on 8 degrees of freedom
## Multiple R-squared:  0.01377,    Adjusted R-squared:  -0.1095 
## F-statistic: 0.1117 on 1 and 8 DF,  p-value: 0.7468
# Previsões para 2026 e 2027
novos_anos <- data.frame(anos = c(2026, 2027))
previsoes_lm <- predict(modelo_lm_doutorado, newdata = novos_anos)

# Resultados
print(ceiling(previsoes_lm[2]))
##    2 
## 4081
# ARIMA com drift
# ts_doutorado <- ts(matriculados, start = 2016, frequency = 1)
# modelo_drift_doutorado <- Arima(ts_doutorado, order = c(0,1,1), include.drift = TRUE)
# forecast_doutorado <- forecast(modelo_drift_doutorado, h = 1)
# 
# autoplot(forecast_doutorado)
# print(ceiling(forecast_doutorado))

Assim, obtemos o valor predito para 2027 de \(4081\) alunos matriculados no doutorado.

Total de Alunos (Soma)

Temos, portanto, a predição para o total de alunos em 2027:

data.frame(grad_presencial = ceiling(media_2027),
           grad_EAD = ceiling(media_ead_2027),
           mestrado = ceiling(previsao_mestrado_LINEAR_MODEL),
           doutorado = ceiling(previsoes_lm[2])) %>% 
  mutate(Total = 
           sum(grad_presencial, grad_EAD, mestrado, doutorado)) %>% 
  select("Graduação Presencial" = grad_presencial,
         "Graduação a Distância" = grad_EAD,
         "Mestrado" = mestrado,
         "Doutorado" = doutorado,
         Total)-> resultado_final

resultado_final %>% reactable(bordered = TRUE, striped = TRUE, 
                              highlight = TRUE, rownames = FALSE)