Universidade Federal de Pernambuco
Diretoria de Avaliação Institucional
O ENAMED (Exame Nacional de Avaliação da Formação Médica) é uma avaliação aplicada no Brasil com o objetivo de medir a qualidade da formação dos estudantes de Medicina. Ele busca verificar se os futuros médicos desenvolveram as competências e habilidades essenciais para o exercício da profissão, como conhecimentos clínicos, raciocínio diagnóstico e tomada de decisão.
Além de servir como um indicador da qualidade dos cursos de Medicina no país, o ENAMED também pode contribuir para o aprimoramento das instituições de ensino, fornecendo dados que ajudam na identificação de pontos fortes e aspectos que precisam ser melhorados na formação médica. Dessa forma, o exame tem um papel importante na garantia de um padrão mínimo de qualidade na formação dos profissionais de saúde.
A prova do ENAMED é estruturada para avaliar, de forma abrangente, os conhecimentos e habilidades essenciais adquiridos ao longo do curso de Medicina. Em geral, ela é composta por questões objetivas de múltipla escolha, organizadas para cobrir as principais áreas da formação médica.
As questões costumam abranger campos fundamentais como Clínica Médica, Cirurgia, Pediatria, Ginecologia e Obstetrícia, Medicina Preventiva e Social (Saúde Coletiva), além de conteúdos relacionados à ética médica e ao raciocínio clínico. A ideia é avaliar não apenas a memorização de conteúdos, mas também a capacidade do estudante de interpretar casos clínicos e tomar decisões adequadas.
Em relação à quantidade, a prova normalmente segue um modelo semelhante a outros exames nacionais da área da saúde, com 100 questões objetivas, distribuídas de forma relativamente equilibrada entre essas áreas.
Quanto ao uso para a residência médica, o desempenho no ENAMED pode ser aproveitado como critério de seleção no ENARE (Exame Nacional de Residência). O ENARE é um processo seletivo unificado que reúne diversas instituições do país para ingresso em programas de residência médica.
Nesse contexto, a nota obtida no ENAMED pode ser utilizada total ou parcialmente na composição da pontuação do candidato no ENARE, dependendo do edital vigente. Isso significa que um bom desempenho no exame pode facilitar o acesso à residência, reduzindo a necessidade de realizar múltiplas provas específicas e ampliando as oportunidades em diferentes instituições.
Assim, o ENAMED não apenas avalia a qualidade da formação médica, mas também pode funcionar como uma porta de entrada para a especialização, integrando-se a processos seletivos nacionais como o ENARE.
Para possibilitar a comparação direta entre estudantes de diferentes cursos, foi necessário realizar um processo de unificação dos cadernos de prova. Visto que o ENAMED utiliza diferentes cadernos (Cores) onde a ordem das questões varia, a análise puramente pela posição da questão no caderno original seria falha.
O processo consistiu em:
Mapeamento via Gabarito: Utilizou-se o vetor de respostas do aluno (TX_RESPOSTAS_OBJETIVA) e o vetor de gabarito (TX_GABARITO_OBJETIVA) correspondente a cada tipo de prova (definido por CO_PROVA).
Normalização das Questões: Cada resposta foi mapeada para um identificador único de item. Dessa forma, a “Questão 1” em nossa análise refere-se ao mesmo objeto de conhecimento para todos os estudantes.
Vetorização de Acertos: Criou-se uma matriz binária onde 1 representa o acerto (concordância entre resposta e gabarito) e 0 o erro, permitindo o cálculo de médias e frequências de acerto por item
library(tidyverse)
library(dplyr)
library(readr)
library(effsize)
library(purrr)
library(knitr)
library(kableExtra)
setwd("G:/Meu Drive/workspace/ENAMED_2025/")
#setwd("H:/Meu Drive/workspace/ENAMED_2025/")
# Enamed 2025 - verificacao resultados ufpe
# Abrindo os dados de respostas dos estudantes
microdados_enade_2025_arq3 <- read_delim("microdados_enamed_2025/DADOS/Enade/microdados_enade_2025_arq3.txt",
delim = ";", escape_double = FALSE, trim_ws = TRUE)
#View(microdados_enade_2025_arq3)
# Abrindo os dados dos parametros das questoes
microdados2025_parametros_itens <- read_delim("microdados_enamed_2025/DADOS/microdados2025_parametros_itens.txt",
delim = ";", escape_double = FALSE, trim_ws = TRUE)
#View(microdados2025_parametros_itens)
# Passo 1: Expandir as respostas dos alunos para 100 colunas
df_expandido <- microdados_enade_2025_arq3 %>%
filter(TP_PR_GER == 555, CO_CADERNO==1) %>% # apenas alunos com presenca valida
separate(
col = DS_VT_ACE_OBJ,
into = paste0("questao_", 1:100),
sep = 1:99,
remove = FALSE # Mantém a coluna original se quiser conferir
)
# Ajuste: se as colunas ficarem com espaços, use trim_ws
df_expandido <- df_expandido %>%
mutate(across(starts_with("questao_"), str_trim))
#glimpse(df_expandido)
# A referencia das questoes eh o CADERNO 1: vamos reordenar as questoes do
# CADERNO 2 de acordo com o caderno 1
# 1. CARREGAR E PREPARAR O MAPEAMENTO (DE-PARA)
# Criamos uma base de 1 a 100 para garantir que nenhuma questão "suma"
mapeamento_completo <- data.frame(NU_ITEM_PROVA_1 = 1:100) %>%
left_join(microdados2025_parametros_itens, by = "NU_ITEM_PROVA_1") %>%
mutate(
# Se a questão não está no arquivo ou ITEM_MANTIDO é 0, ela deve ser anulada
deve_anular = is.na(ITEM_MANTIDO) | ITEM_MANTIDO == 0
)
# Vetor de nomes de colunas que DEVEM ser NA (Ex: questao_2, questao_7, questao_11...)
colunas_para_anular <- mapeamento_completo %>%
filter(deve_anular == TRUE) %>%
pull(NU_ITEM_PROVA_1) %>%
paste0("questao_", .)
# Função para limpar códigos de anulação específicos do vetor (6 e 8)
limpar_6_8 <- function(x) {
x %>% na_if("6") %>% na_if("8")
}
# 2. TRATAMENTO DO CADERNO 1
df_caderno1 <- microdados_enade_2025_arq3 %>%
filter(TP_PR_GER == 555, CO_CADERNO == 1) %>%
separate(col = DS_VT_ACE_OBJ, into = paste0("questao_", 1:100), sep = 1:99) %>%
mutate(across(starts_with("questao_"), ~ limpar_6_8(str_trim(.x))))
# 3. TRATAMENTO DO CADERNO 2 (COM REORDENAÇÃO PRECISA)
df_caderno2_raw <- microdados_enade_2025_arq3 %>%
filter(TP_PR_GER == 555, CO_CADERNO == 2) %>%
separate(col = DS_VT_ACE_OBJ, into = paste0("questao_", 1:100), sep = 1:99)
# Reorganizar as colunas do Caderno 2
matriz_c2 <- df_caderno2_raw %>% select(starts_with("questao_"))
# Aqui está o pulo do gato: usamos o NU_ITEM_PROVA_2 do mapeamento ordenado pelo 1
# Se o mapeamento for NA (questão inexistente), usamos uma coluna temporária de NAs
ordem_c2 <- paste0("questao_", mapeamento_completo$NU_ITEM_PROVA_2)
ordem_c2[is.na(mapeamento_completo$NU_ITEM_PROVA_2)] <- NA
# Criamos a nova matriz (quem for NA no mapa vira NA na matriz)
matriz_reordenada <- as.data.frame(matrix(NA, nrow = nrow(matriz_c2), ncol = 100))
colnames(matriz_reordenada) <- paste0("questao_", 1:100)
for(i in 1:100) {
col_origem <- ordem_c2[i]
if(!is.na(col_origem)) {
matriz_reordenada[, i] <- matriz_c2[[col_origem]]
}
}
# Limpar códigos 6 e 8 e remover espaços
matriz_reordenada <- matriz_reordenada %>%
mutate(across(everything(), ~ limpar_6_8(str_trim(.x))))
# Montar o dataframe do Caderno 2
df_caderno2_final <- df_caderno2_raw %>%
select(-starts_with("questao_")) %>%
bind_cols(matriz_reordenada)
# 4. JUNÇÃO FINAL E ANULAÇÃO FORÇADA
df_final_padronizado <- bind_rows(df_caderno1, df_caderno2_final) %>%
# Força NA nas questões que não estão no arquivo ou foram marcadas como ITEM_MANTIDO = 0
mutate(across(any_of(colunas_para_anular), ~ NA_character_)) %>%
# Converter para numérico
mutate(across(starts_with("questao_"), as.numeric))
# 5. RESULTADO FILTRADO (As 93 questões válidas)
df_enamed_93 <- df_final_padronizado %>%
select(
where(~ !all(is.na(.))))
Após a unificação dos cadernos, procedeu-se à identificação dos itens que apresentaram maior desafio para cada grupo. Para esta análise, utilizamos dois indicadores complementares:
Índice de Facilidade Empírico: Representa a proporção real de acertos dos alunos em cada questão (variando de 0 a 1).
Parâmetro B (Dificuldade Teórica): Proveniente da Teoria de Resposta ao Item (TRI), indica o nível de proficiência necessário para que um candidato tenha 50% de probabilidade de acertar o item.
# analise por curso -------------------------------------------------------
# codigos de curso:
# Medicina CCM: 13601
# Medicina CAA: 1189778
# funcao que gera Ranking de questoes mais dificeis - referencia caderno 1
#' Gerar Ranking de Dificuldade por Curso
#' @param cod_curso Código numérico do curso (CO_CURSO)
#' @param dados Dataframe processado (df_enamed_93)
#' @param mapa Dataframe de mapeamento (mapeamento_completo)
#' @return Um dataframe ordenado da questão mais difícil para a mais fácil
gerar_ranking_curso <- function(cod_curso, dados = df_enamed_93,
mapa = mapeamento_completo) {
# 1. Filtro e Cálculo das Médias (Facilidade Empírica)
ranking <- dados %>%
filter(CO_CURSO == cod_curso) %>%
select(starts_with("questao_")) %>%
summarise(across(everything(), ~ mean(.x, na.rm = TRUE))) %>%
pivot_longer(
cols = everything(),
names_to = "questao",
values_to = "indice_facilidade"
)
# 2. Cruzamento com Parâmetros Originais
# Adicionamos o NU_ITEM_PROVA_1 e o PARAMETRO_B para contexto
ranking_final <- ranking %>%
left_join(
mapa %>% mutate(questao = paste0("questao_", NU_ITEM_PROVA_1)),
by = "questao"
) %>%
# 3. Ordenação: Menor facilidade (mais difícil) primeiro
arrange(indice_facilidade) %>%
select(questao, indice_facilidade, PARAMETRO_B, ITEM_MANTIDO)
return(ranking_final)
}
A tabela abaixo apresenta o ranking das 10 questões com os menores índices de facilidade para cada instituição. Este ranking é fundamental para identificar lacunas pedagógicas específicas.
No curso CCM, a Questão 59 destaca-se como a mais difícil, com apenas 9,86% de acerto. Nota-se uma correlação com o Parâmetro B (2.42), confirmando que se trata de uma questão tecnicamente muito exigente.
# Para o curso 13601:
ranking_CCM <- gerar_ranking_curso(13601)
knitr::kable(head(ranking_CCM, 10),
digits = 2,
row.names = FALSE,
caption = "Top 10 Questões mais difíceis - CCM (13601)",
col.names = c("Questão", "Facilidade (Média)", "Parâmetro B (TRI)",
"Item Mantido")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Questão | Facilidade (Média) | Parâmetro B (TRI) | Item Mantido |
|---|---|---|---|
| questao_59 | 0.10 | 2.42 | 1 |
| questao_72 | 0.22 | 1.70 | 1 |
| questao_57 | 0.28 | 1.19 | 1 |
| questao_58 | 0.28 | 0.71 | 1 |
| questao_97 | 0.30 | 1.12 | 1 |
| questao_19 | 0.31 | 0.82 | 1 |
| questao_48 | 0.35 | 1.77 | 1 |
| questao_28 | 0.37 | 0.13 | 1 |
| questao_38 | 0.38 | 0.44 | 1 |
| questao_96 | 0.38 | 0.61 | 1 |
Para o curso do CAA, a Questão 59 também lidera o ranking de dificuldade, porém com um desempenho ainda mais reduzido (6,33%). Um ponto de atenção imediato é a Questão 16, que aparece entre as mais difíceis para este grupo (20,3% de acerto), mas não figura no Top 10 de dificuldade do curso CCM, sugerindo um conteúdo de domínio desigual entre os cursos.
# Para o curso 1189778:
ranking_CAA <- gerar_ranking_curso(1189778)
knitr::kable(head(ranking_CAA, 10),
digits = 2,
row.names = FALSE,
caption = "Top 10 Questões mais difíceis - CAA (1189778)",
col.names = c("Questão", "Facilidade (Média)", "Parâmetro B (TRI)",
"Item Mantido")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Questão | Facilidade (Média) | Parâmetro B (TRI) | Item Mantido |
|---|---|---|---|
| questao_59 | 0.06 | 2.42 | 1 |
| questao_28 | 0.15 | 0.13 | 1 |
| questao_72 | 0.16 | 1.70 | 1 |
| questao_97 | 0.16 | 1.12 | 1 |
| questao_48 | 0.18 | 1.77 | 1 |
| questao_16 | 0.20 | 0.64 | 1 |
| questao_57 | 0.24 | 1.19 | 1 |
| questao_58 | 0.32 | 0.71 | 1 |
| questao_98 | 0.32 | 0.01 | 1 |
| questao_4 | 0.35 | -0.13 | 1 |
A análise cruzada entre a facilidade observada e o Parâmetro B permite observar fenômenos de “acerto casual” ou falhas de instrução:
Questões com Alto Parâmetro B e Baixo Índice de Facilidade (como a Q59 e Q72) são esperadas e validam a consistência da prova.
Questões com Baixo Parâmetro B que aparecem entre as mais difíceis (como a Questão 28 para o curso CAA, com facilidade de 0.15 e B de apenas 0.12) indicam pontos de atenção crítica. Nesses casos, o item é considerado “fácil” pela régua estatística geral, mas foi “difícil” para o grupo específico, sinalizando uma possível defasagem em conteúdos básicos.
Enquanto a análise anterior focou em questões isoladas, esta seção agrupa o desempenho dos estudantes nas cinco grandes áreas que compõem o ENAMED. Esta visão estruturada permite identificar se a diferença de performance entre as instituições é generalizada ou concentrada em domínios específicos. As tabelas abaixo resumem a quantidade média de acertos em cada área (com escala de 0 a 20 questões por bloco) e o percentual de acerto geral no exame.
# quantidade de acertos por area
#' Analisar Desempenho por Áreas e Geral
#' @param cod_curso Código numérico do CO_CURSO
#' @param dados Dataframe que contém as colunas QT_ACERTO_AREA_X e PER_ACERTO_ENARE
#' @return Um resumo com a média de acertos de cada área para o curso selecionado
analisar_performance_areas <- function(cod_curso, dados = df_enamed_93) {
# 1. Definir as colunas de interesse
colunas_performance <- c(
"QT_ACERTO_AREA_1", "QT_ACERTO_AREA_2",
"QT_ACERTO_AREA_3", "QT_ACERTO_AREA_4",
"QT_ACERTO_AREA_5", "PER_ACERTO_ENARE"
)
# 2. Filtrar e Calcular as Médias
resumo <- dados %>%
filter(CO_CURSO == cod_curso) %>%
# Garante que estamos pegando apenas as colunas que existem no seu DF
select(any_of(colunas_performance)) %>%
summarise(across(everything(), ~ mean(.x, na.rm = TRUE))) %>%
# Organizar para leitura vertical
pivot_longer(
cols = everything(),
names_to = "Indicador",
values_to = "Media_Acertos"
) %>%
mutate(
Descricao = case_when(
Indicador == "QT_ACERTO_AREA_1" ~ "Área 1 - Clínica Médica",
Indicador == "QT_ACERTO_AREA_2" ~ "Área 2 - Pediatria",
Indicador == "QT_ACERTO_AREA_3" ~ "Área 3 - Cirurgia Geral",
Indicador == "QT_ACERTO_AREA_4" ~ "Área 4 - Ginecologia e Obstetrícia",
Indicador == "QT_ACERTO_AREA_5" ~ "Área 5 - Medicina da Família e Comunidade/Saúde Coletiva",
Indicador == "PER_ACERTO_ENARE" ~ "Percentual Total Geral (%)",
TRUE ~ Indicador
)
) %>%
select(Indicador, Descricao, Media_Acertos)
return(resumo)
}
Ao confrontar os dados das duas instituições, observamos padrões distintos de formação:
O Diferencial da Cirurgia Geral (Área 3): Esta é a área com maior disparidade. O curso CCM (11,21) supera o curso CAA (9,94) em mais de 1,2 pontos na média de acertos. Considerando que cada bloco possui 20 questões, essa variação sugere uma maturidade pedagógica superior no eixo cirúrgico para a instituição CCM.
Equilíbrio em Clínica Médica (Área 1): o curso CAA (12,34) apresenta uma leve vantagem sobre o CCM (12,04) neste eixo, mostrando que a base de medicina interna é sólida e competitiva em ambas as instituições.
Saúde Coletiva (Área 5): Ambas as instituições apresentam seu maior número de acertos absolutos neste bloco (médias > 13), o que pode indicar tanto uma boa preparação acadêmica quanto um nível de dificuldade menor nos itens desta área na edição avaliada.
perf_CCM <- analisar_performance_areas(13601)
knitr::kable(perf_CCM %>% select(Descricao, Media_Acertos),
digits = 2,
row.names = FALSE,
col.names = c("Eixo Temático", "Média de Acertos"),
caption = "Desempenho por Área - Curso CCM")
| Eixo Temático | Média de Acertos |
|---|---|
| Área 1 - Clínica Médica | 11.96 |
| Área 2 - Pediatria | 12.48 |
| Área 3 - Cirurgia Geral | 11.25 |
| Área 4 - Ginecologia e Obstetrícia | 12.07 |
| Área 5 - Medicina da Família e Comunidade/Saúde Coletiva | 13.77 |
| Percentual Total Geral (%) | 71.52 |
perf_CAA <- analisar_performance_areas(1189778)
knitr::kable(perf_CAA %>% select(Descricao, Media_Acertos),
digits = 2,
row.names = FALSE,
col.names = c("Eixo Temático", "Média de Acertos"),
caption = "Desempenho por Área - Curso CAA")
| Eixo Temático | Média de Acertos |
|---|---|
| Área 1 - Clínica Médica | 12.29 |
| Área 2 - Pediatria | 11.99 |
| Área 3 - Cirurgia Geral | 9.94 |
| Área 4 - Ginecologia e Obstetrícia | 11.66 |
| Área 5 - Medicina da Família e Comunidade/Saúde Coletiva | 13.44 |
| Percentual Total Geral (%) | 69.32 |
Para determinar se a vantagem de 2,2 pontos percentuais do curso CCM (71,5%) sobre o curso CAA (69,3%) reflete uma superioridade acadêmica real ou se é fruto do acaso amostral, aplicamos o Teste t de Welch e o cálculo do Tamanho do Efeito (Cohen’s d).
# testes de hipoteses -----------------------------------------------------
# Comparando o Curso 13601 com o Curso 99999
curso_CCM <- df_enamed_93 %>% filter(CO_CURSO == 13601) %>% pull(PER_ACERTO_ENARE)
curso_CAA <- df_enamed_93 %>% filter(CO_CURSO == 1189778) %>% pull(PER_ACERTO_ENARE)
t.test(curso_CCM, curso_CAA)
##
## Welch Two Sample t-test
##
## data: curso_CCM and curso_CAA
## t = 1.7635, df = 188.9, p-value = 0.07943
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.2614065 4.6707486
## sample estimates:
## mean of x mean of y
## 71.52113 69.31646
# Cálculo do Tamanho do Efeito
effsize::cohen.d(curso_CCM, curso_CAA)
##
## Cohen's d
##
## d estimate: 0.2340219 (small)
## 95 percent confidence interval:
## lower upper
## -0.04347274 0.51151659
# Resumo da Ópera: O CCM foi melhor na média? Sim. Essa vantagem é relevante?
# Provavelmente não muito. Se você fosse o coordenador do curso CAA, esse
# resultado te diria que seus alunos estão "andando junto" com o CCM,
# sem uma defasagem preocupante.
Utilizou-se o Teste t para amostras independentes, que resultou em um p-valor = 0,079.
Interpretação: Adotando o nível de significância padrão de 5% (\(\alpha = 0,05\)), não há evidências estatísticas suficientes para afirmar que os cursos possuem desempenhos distintos no percentual geral.Intervalo de Confiança: O intervalo de confiança de 95% para a diferença entre as médias cruza o zero (variando de -0,26 a +4,67), o que reforça que a diferença observada é estatisticamente frágil.
Para medir a magnitude da diferença, calculamos o D de Cohen, que resultou em 0,23.
Magnitude: Este valor é classificado como pequeno (small).
Ou seja, mesmo que a média do CCM seja numericamente superior, as distribuições de notas dos dois cursos estão fortemente sobrepostas. A “vantagem” do CCM não é grande o suficiente para sugerir que um aluno médio de uma instituição tenha um nível de conhecimento drasticamente diferente de um aluno da outra.
Do ponto de vista de gestão acadêmica e coordenação de curso, os resultados trazem as seguintes conclusões:
Paridade Competitiva: O curso CAA (1189778) está “andando junto” com o curso CCM (13601). Não existe uma defasagem preocupante que exija reformas estruturais urgentes.
Foco em Gargalos Específicos: Como a diferença geral não é significativa, o foco da coordenação não deve ser o “todo”, mas sim os pontos identificados na análise por áreas (como a Cirurgia Geral), onde vimos anteriormente que a distância é mais acentuada.
Estabilidade Pedagógica: Ambas as instituições demonstram um padrão de entrega similar, com o curso CCM apresentando apenas uma leve vantagem de performance que, nesta amostra, não atinge o rigor da significância estatística.
Para entender as causas das variações nas médias de cada curso, realizamos uma comparação item a item. Utilizamos o Teste Exato de Fisher, que é o padrão estatístico mais rigoroso para comparar proporções de acertos entre dois grupos, especialmente quando há grande variação no desempenho.Nesta seção, isolamos apenas as questões onde houve significância estatística (\(p < 0,05\)), ou seja, onde a diferença de acertos entre CCM e CAA não pode ser atribuída ao acaso.
A tabela abaixo apresenta os itens em que um dos cursos obteve vantagem estatística relevante, ordenada pelo nível de confiança (\(p\)-valor).
# 2. Teste de Proporção (Para comparar uma Questão Específica)
#' Comparar Proporção de Acertos entre Dois Cursos
#' @param dados Dataframe processado (ex: df_enamed_93)
#' @param cod_A Código do primeiro curso
#' @param cod_B Código do segundo curso
#' @param num_questao Número da questão (inteiro)
#' @return Resultado do prop.test ou uma mensagem de erro amigável
comparar_questao <- function(dados, cod_A, cod_B, num_questao) {
nome_col <- paste0("questao_", num_questao)
if (!nome_col %in% colnames(dados)) {
return(paste0("Erro: A questão ", num_questao, " não encontrada."))
}
resumo <- dados %>%
filter(CO_CURSO %in% c(cod_A, cod_B)) %>%
group_by(CO_CURSO) %>%
summarise(
acertos = sum(!!sym(nome_col) == 1, na.rm = TRUE),
total = sum(!is.na(!!sym(nome_col))),
erros = total - acertos, # Precisamos dos erros para o Fisher
.groups = 'drop'
)
if (nrow(resumo) < 2) return("Erro: Dados insuficientes.")
# Criar uma matriz de contingência para o Teste de Fisher
# Linhas: Cursos | Colunas: Acertos e Erros
matriz_contingencia <- matrix(
c(resumo$acertos[1], resumo$erros[1],
resumo$acertos[2], resumo$erros[2]),
nrow = 2, byrow = TRUE
)
# Executa o Teste Exato de Fisher (mais robusto para números pequenos)
teste <- fisher.test(matriz_contingencia)
return(list(
questao = nome_col,
cursos = resumo$CO_CURSO,
proporcoes = resumo$acertos / resumo$total,
p_valor = teste$p.value, # O Fisher também retorna um p-valor
resultado_completo = teste
))
}
# Vamos executar o teste de proporcao para todas as questoes e descobrir
# em quais dela ha diferenca entre os dois cursos:
# 1. Definir os cursos para comparação
curso_A <- 13601
curso_B <- 1189778
# 2. Criar uma lista para armazenar os resultados
resultados_lista <- list()
# 3. Loop pelas questões disponíveis
questoes_disponiveis <- names(df_enamed_93)[str_detect(names(df_enamed_93), "questao_")]
for (q in questoes_disponiveis) {
num_q <- as.numeric(str_extract(q, "\\d+"))
# Executa a função de comparação
res <- comparar_questao(df_enamed_93, curso_A, curso_B, num_q)
if (is.list(res)) {
# Busca o parâmetro B
info_item <- mapeamento_completo %>%
filter(NU_ITEM_PROVA_1 == num_q) %>%
select(PARAMETRO_B) %>%
first()
resultados_lista[[q]] <- data.frame(
questao = res$questao,
num_original = num_q,
prop_A = res$proporcoes[1],
prop_B = res$proporcoes[2],
diferenca = res$proporcoes[1] - res$proporcoes[2],
p_valor = res$p_valor,
parametro_b = info_item$PARAMETRO_B
)
}
}
# 4. Consolidar, filtrar significativas e adicionar coluna de vencedor
df_comparativo_final <- bind_rows(resultados_lista) %>%
filter(p_valor < 0.05) %>%
mutate(
melhor_curso = if_else(diferenca > 0, as.character(curso_A), as.character(curso_B)),
# Adicionamos também uma coluna de "Vantagem" em valor absoluto para facilitar a leitura
vantagem_abs = abs(diferenca) * 100
) %>%
select(questao, melhor_curso, vantagem_abs, p_valor, parametro_b, prop_A, prop_B) %>%
arrange(p_valor)
# Exibir o resultado
knitr::kable(df_comparativo_final,
digits = 4,
row.names = FALSE,
col.names = c("Questão", "Melhor Curso", "Vantagem (%)", "p-valor", "Parâmetro B", "Prop. CCM", "Prop. CAA"),
caption = "Questões com Diferenças Estatisticamente Significativas entre os Cursos") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Questão | Melhor Curso | Vantagem (%) | p-valor | Parâmetro B | Prop. CCM | Prop. CAA |
|---|---|---|---|---|---|---|
| questao_16 | 13601 | 46.6482 | 0.0000 | 0.6414 | 0.6690 | 0.2025 |
| questao_4 | 13601 | 25.8246 | 0.0003 | -0.1295 | 0.6127 | 0.3544 |
| questao_28 | 13601 | 21.4298 | 0.0007 | 0.1285 | 0.3662 | 0.1519 |
| questao_87 | 13601 | 22.8829 | 0.0009 | -0.2664 | 0.6972 | 0.4684 |
| questao_78 | 1189778 | 15.0829 | 0.0063 | -1.8426 | 0.7606 | 0.9114 |
| questao_22 | 13601 | 16.9906 | 0.0067 | -0.7156 | 0.8028 | 0.6329 |
| questao_98 | 13601 | 19.0587 | 0.0072 | 0.0086 | 0.5070 | 0.3165 |
| questao_48 | 13601 | 16.7855 | 0.0084 | 1.7700 | 0.3451 | 0.1772 |
| questao_75 | 13601 | 17.8017 | 0.0120 | 0.1624 | 0.5704 | 0.3924 |
| questao_47 | 13601 | 16.1437 | 0.0122 | -1.2002 | 0.7817 | 0.6203 |
| questao_71 | 1189778 | 16.2239 | 0.0135 | -0.1125 | 0.6479 | 0.8101 |
| questao_74 | 13601 | 10.8219 | 0.0148 | -1.3238 | 0.9437 | 0.8354 |
| questao_70 | 13601 | 16.8301 | 0.0155 | -0.0595 | 0.6620 | 0.4937 |
| questao_86 | 1189778 | 14.6728 | 0.0188 | -0.7324 | 0.6761 | 0.8228 |
| questao_35 | 1189778 | 13.8260 | 0.0246 | -0.0748 | 0.6972 | 0.8354 |
| questao_18 | 13601 | 15.8317 | 0.0256 | 0.6268 | 0.5634 | 0.4051 |
| questao_49 | 13601 | 13.8884 | 0.0339 | -0.7081 | 0.7465 | 0.6076 |
| questao_97 | 13601 | 13.1218 | 0.0350 | 1.1210 | 0.2958 | 0.1646 |
| questao_8 | 1189778 | 13.2644 | 0.0380 | -0.1349 | 0.6901 | 0.8228 |
| questao_56 | 13601 | 14.0132 | 0.0473 | 0.0950 | 0.6338 | 0.4937 |
A análise detalhada dos 20 itens acima revela pontos fundamentais para o diagnóstico pedagógico:
A Questão 16 (sempre tendo como referência o Caderno 1) apresenta a maior disparidade de toda a prova. O curso CCM obteve 66,9% de acerto contra apenas 20,2% do curso CAA (uma vantagem de 46,6%). Com um \(p\)-valor de \(10^{-11}\), esta diferença é massiva. O Parâmetro B (0,64) indica uma questão de dificuldade média.
O curso do CCM superou o do CAA em questões de alta dificuldade teórica, como a Questão 48 (B = 1,77) e a Questão 97 (B = 1,12). Isso indica que os alunos do CCM estão mais bem preparados para os itens que “separam” os candidatos de elite. Por outro lado, o curso CAA superou o CCM em questões de nível fácil/médio, como a Questão 78 (B = -1,84) e a Questão 71 (B = -0,11), mostrando domínio em competências mais básicas ou fundamentais.
Esta análise mostra que, embora a média geral dos cursos seja próxima, o curso CCM possui uma “frente de ataque” mais robusta em temas específicos (especialmente naqueles representados pelas questões 16, 4 e 28). Para o curso CAA, estas 15 questões onde o desempenho foi inferior representam o mapa de revisão curricular prioritário.
Diferente da média de acertos brutos, a Proficiência (TRI) pondera o desempenho do estudante com base na dificuldade dos itens que ele acertou ou errou. Esta medida oferece uma visão mais precisa da habilidade real dos estudantes.
Para verificar a robustez da diferença entre os cursos, aplicamos duas abordagens estatísticas: o Teste t de Welch (paramétrico) e o Teste de Wilcoxon (não paramétrico).
# teste t para diferenca de proficiencia
# 1. Preparar os vetores de proficiência
prof_13601 <- df_enamed_93 %>% filter(CO_CURSO == 13601) %>% pull(PROFICIENCIA)
prof_1189778 <- df_enamed_93 %>% filter(CO_CURSO == 1189778) %>% pull(PROFICIENCIA)
# 2. Executar o Teste t de Welch (ajustado para variâncias diferentes)
teste_tri <- t.test(prof_13601, prof_1189778)
# 3. Calcular o Tamanho do Efeito (Cohen's d) - ESSENCIAL AQUI
efeito_tri <- cohen.d(prof_13601, prof_1189778)
# Exibir resultados
print(teste_tri)
##
## Welch Two Sample t-test
##
## data: prof_13601 and prof_1189778
## t = 1.9671, df = 196.26, p-value = 0.05058
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.0003675825 0.2879687591
## sample estimates:
## mean of x mean of y
## 0.22021831 0.07641772
print(efeito_tri)
##
## Cohen's d
##
## d estimate: 0.2570392 (small)
## 95 percent confidence interval:
## lower upper
## -0.02063436 0.53471280
# 1. Executar o Teste de Wilcoxon (Mann-Whitney)
teste_nao_param <- wilcox.test(prof_13601, prof_1189778, conf.int = TRUE)
# 2. Calcular o Tamanho do Efeito (Cliff's Delta é o ideal para não paramétricos)
efeito_nao_param <- cliff.delta(prof_13601, prof_1189778)
# Exibir resultados
print(teste_nao_param)
##
## Wilcoxon rank sum test with continuity correction
##
## data: prof_13601 and prof_1189778
## W = 6297, p-value = 0.131
## alternative hypothesis: true location shift is not equal to 0
## 95 percent confidence interval:
## -0.0530615 0.2690840
## sample estimates:
## difference in location
## 0.1159422
print(efeito_nao_param)
##
## Cliff's Delta
##
## delta estimate: 0.12266 (negligible)
## 95 percent confidence interval:
## lower upper
## -0.03178037 0.27137973
O Teste t apresentou um p-valor de 0,0505, o que indica uma significância marginal. Existe uma tendência de superioridade numérica do curso CCM (\(\bar{x}=0,22\)) sobre o CAA (\(\bar{x}=0,07\)), mas ela não atinge o rigor estatístico convencional de 5%.
Quando utilizamos o teste de Wilcoxon — que é menos sensível a notas extremas (outliers) e foca na distribuição das medianas — o p-valor sobe para 0,131, e o efeito é classificado como negligenciável.
O achado mais relevante desta seção surge ao cruzarmos estes dados com a análise de itens feita anteriormente. Temos um cenário estatístico único:
Diferença Absurda em Itens Específicos: Vimos que em questões como a Questão 16, a diferença de acertos foi massiva (\(p = 10^{-11}\)).
Sobreposição na Proficiência Geral: No entanto, quando olhamos para a “nota TRI” total, os alunos de ambos os grupos estão muito próximos e as d istribuições se sobrepõem consideravelmente.
Este padrão revela que a diferença entre o curso CCM e o curso CAA não é uma questão de capacidade intelectual geral dos estudantes, mas sim de exposição a conteúdos específicos.
Se a diferença fosse generalizada, a proficiência TRI seria drasticamente distinta. Como a proficiência geral é próxima, mas questões específicas são “abismos”, fica provado que o curso CCM obteve sucesso em ensinar tópicos específicos (especialmente em Cirurgia e pontos chaves de Clínica) que o curso CAA possivelmente não abordou com a mesma profundidade.
Para finalizar a investigação, decompusemos a performance global em cada um dos cinco eixos temáticos do ENAMED. Esta análise isola o efeito de cada especialidade na nota final e revela o “ponto de inflexão” entre as duas instituições.
Utilizamos o Teste t de Welch para comparar as médias e o \(d\) de Cohen para medir a relevância prática de cada diferença.
# teste por area ----------------------------------------------------------
# 1. Definir os códigos e nomes separadamente
codigos_areas <- c("QT_ACERTO_AREA_1", "QT_ACERTO_AREA_2", "QT_ACERTO_AREA_3",
"QT_ACERTO_AREA_4", "QT_ACERTO_AREA_5")
nomes_exibicao <- c("Clínica Médica", "Pediatria", "Cirurgia Geral",
"Ginecologia e Obstetrícia", "Medicina da Família")
# 2. A função comparar_areas permanece a mesma que você já tem
comparar_areas <- function(nome_exibicao, coluna_dados, dados, cod_A, cod_B) {
grupo_A <- dados %>% filter(CO_CURSO == cod_A) %>% pull(!!sym(coluna_dados))
grupo_B <- dados %>% filter(CO_CURSO == cod_B) %>% pull(!!sym(coluna_dados))
grupo_A <- grupo_A[!is.na(grupo_A)]
grupo_B <- grupo_B[!is.na(grupo_B)]
t_test <- t.test(grupo_A, grupo_B)
d_cohen <- cohen.d(grupo_A, grupo_B)
return(data.frame(
Area = nome_exibicao,
Media_13601 = t_test$estimate[1],
Media_1189778 = t_test$estimate[2],
Diferenca = t_test$estimate[1] - t_test$estimate[2],
p_valor = t_test$p.value,
Cohen_d = d_cohen$estimate,
Magnitude = d_cohen$magnitude
))
}
# 3. Executar usando map2_df (que costuma estar disponível em versões mais antigas do purrr)
resultado_areas <- map2_df(nomes_exibicao, codigos_areas,
~comparar_areas(.x, .y, df_enamed_93, 13601, 1189778))
# 4. Exibir o resultado
resultado_areas %>%
arrange(p_valor) %>%
knitr::kable(
digits = 3,
row.names = FALSE,
col.names = c("Área do Conhecimento", "Média CCM", "Média CAA", "Diferença",
"p-valor", "Cohen's d", "Magnitude"),
caption = "Análise Comparativa de Desempenho por Eixo Temático"
) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
row_spec(1, bold = T, background = "#f2dede") # Destaca a Cirurgia Geral
| Área do Conhecimento | Média CCM | Média CAA | Diferença | p-valor | Cohen’s d | Magnitude |
|---|---|---|---|---|---|---|
| Cirurgia Geral | 11.246 | 9.937 | 1.310 | 0.000 | 0.548 | medium |
| Pediatria | 12.479 | 11.987 | 0.492 | 0.126 | 0.211 | small |
| Ginecologia e Obstetrícia | 12.070 | 11.658 | 0.412 | 0.248 | 0.159 | negligible |
| Medicina da Família | 13.768 | 13.443 | 0.325 | 0.297 | 0.142 | negligible |
| Clínica Médica | 11.958 | 12.291 | -0.333 | 0.358 | -0.123 | negligible |
Os dados revelam um cenário de paridade técnica em 80% das áreas avaliadas, com uma exceção crítica:
A análise comparativa detalhada entre os cursos 13601 (CCM) e 1189778 (CAA), baseada nos microdados do ENAMED, permite uma compreensão profunda que vai além da superfície das notas médias. Os dados revelam um cenário de equilíbrio técnico pontuado por disparidades pedagógicas específicas.
Paridade de Proficiência: Os testes de hipóteses sobre a proficiência global (TRI) e o percentual de acertos não demonstraram uma superioridade estatística robusta do curso CCM. Com um p-valor de 0,0505 e um tamanho de efeito pequeno (\(d=0,25\)), conclui-se que a base de conhecimento geral dos estudantes em ambas as instituições é comparável.
Identificamos que a diferença numérica entre os cursos reside, de forma quase isolada, na Área 3 (Cirurgia Geral). Foi a única área com significância estatística clara (\(p < 0,0001\)), sendo o principal motor da vantagem do curso CCM no ranking geral.
A análise de itens (Teste de Fisher) provou que as maiores distâncias ocorrem em questões específicas (como a Questão 16, com 46% de diferença). Isso sugere que a diferença de desempenho não é fruto de uma menor capacidade dos alunos do curso CAA.
Para a gestão acadêmica, especialmente do curso 1189778 (CAA), recomendam-se as seguintes ações:
Este relatório demonstra que, em avaliações de larga escala como o ENAMED, a métrica final (nota) muitas vezes esconde nuances importantes. O curso CAA demonstra ser uma instituição com excelente potencial de entrega, necessitando apenas de ajustes finos e setoriais para atingir e superar os níveis de performance das instituições de referência no país.