O ensino superior costuma ser apresentado como um investimento: o estudante paga mensalidades, assume custos de permanência, dedica anos de estudo e espera obter melhores oportunidades de renda no futuro. Porém, esse investimento não é igual para todos. Instituições públicas, privadas sem fins lucrativos e privadas com fins lucrativos podem apresentar diferenças expressivas de custo, seletividade, permanência, conclusão de curso, endividamento e renda posterior dos estudantes.
O problema investigado neste relatório é: quais características das instituições de ensino superior estão associadas a melhores resultados acadêmicos e financeiros para os estudantes? A pergunta é relevante porque ajuda estudantes, famílias, gestores educacionais e formuladores de políticas públicas a comparar instituições de forma mais informada. Não basta saber se uma faculdade é cara ou famosa; é necessário observar se os estudantes permanecem, concluem o curso, assumem dívidas sustentáveis e alcançam renda compatível após a formação.
Para responder a essa questão, utilizo dados públicos do College Scorecard, mantido pelo U.S. Department of Education. A análise combina dados institucionais, como localização, tipo de controle, custo, taxa de admissão, taxa de conclusão e renda mediana após 10 anos, com dados por área de estudo, como dívida mediana e ganhos um ano após a conclusão. A metodologia adotada é exploratória: importação de dados diretamente da web, seleção de variáveis relevantes, padronização de nomes e tipos, tratamento de valores ausentes, criação de variáveis derivadas, junção entre tabelas e construção de gráficos e tabelas para identificar padrões.
A análise não pretende provar causalidade. O objetivo é construir uma narrativa baseada em evidências descritivas: entender como custo, seletividade, tipo de instituição e área de estudo se relacionam com indicadores de resultado. Isso pode auxiliar potenciais usuários da análise a fazer perguntas melhores antes de escolher uma instituição ou avaliar políticas educacionais.
| Pacote | Propósito no projeto |
|---|---|
| tidyverse | Importação, transformação, sumarização e visualização dos dados com readr, dplyr, tidyr, stringr e ggplot2. |
| janitor | Padronização dos nomes das variáveis para formato limpo e consistente. |
| lubridate | Registro e manipulação simples de datas usadas no relatório. |
| scales | Formatação de valores monetários, percentuais e números nos gráficos e tabelas. |
| DT | Criação de tabelas interativas pesquisáveis e ordenáveis. |
| plotly | Conversão de gráficos ggplot2 em visualizações interativas. |
| knitr | Geração de tabelas e integração entre texto, código e resultados. |
| kableExtra | Melhoria visual de tabelas estáticas no HTML final. |
| htmltools | Ajustes de elementos HTML usados nas tabelas interativas. |
Todos os pacotes são carregados no início do documento para que a análise seja reprodutível. O bloco de configuração também instala pacotes ausentes automaticamente, o que facilita a renderização em uma instalação nova do RStudio.
Os dados foram obtidos no portal oficial do College Scorecard, mantido pelo U.S. Department of Education. A atualização citada no portal de dados utilizada aqui é de 23 de março de 2026.
Foram usadas duas bases:
Esses dados foram originalmente coletados para aumentar a transparência sobre instituições de ensino superior nos Estados Unidos, permitindo comparar custos, matrícula, seletividade, permanência, conclusão, dívida estudantil, pagamento de empréstimos e ganhos posteriores. A base institucional contém milhares de instituições e centenas de variáveis. A base por área de estudo contém milhares de combinações entre instituição, curso, nível de credencial, dívida e renda.
Algumas peculiaridades importantes da fonte são:
NULL ou PrivacySuppressed.UNITID.dir.create("data/raw", recursive = TRUE, showWarnings = FALSE)
institution_url <- "https://ed-public-download.scorecard.network/downloads/Most-Recent-Cohorts-Institution_03232026.zip"
field_url <- "https://ed-public-download.scorecard.network/downloads/Most-Recent-Cohorts-Field-of-Study_03232026.zip"
institution_zip <- "data/raw/Most-Recent-Cohorts-Institution_03232026.zip"
field_zip <- "data/raw/Most-Recent-Cohorts-Field-of-Study_03232026.zip"
download_if_missing <- function(url, destination) {
if (!file.exists(destination)) {
download.file(url, destination, mode = "wb", quiet = TRUE)
}
}
download_if_missing(institution_url, institution_zip)
download_if_missing(field_url, field_zip)
extract_first_csv <- function(zip_path, output_dir) {
csv_name <- unzip(zip_path, list = TRUE) |>
as_tibble() |>
filter(str_detect(Name, "\\.csv$")) |>
slice(1) |>
pull(Name)
output_path <- file.path(output_dir, basename(csv_name))
if (!file.exists(output_path)) {
unzip(zip_path, files = csv_name, exdir = output_dir, overwrite = TRUE)
extracted_path <- file.path(output_dir, csv_name)
if (!identical(normalizePath(extracted_path, mustWork = FALSE), normalizePath(output_path, mustWork = FALSE))) {
file.rename(extracted_path, output_path)
}
}
output_path
}
institution_csv <- extract_first_csv(institution_zip, "data/raw")
field_csv <- extract_first_csv(field_zip, "data/raw")O código acima baixa os arquivos compactados apenas se eles ainda não existirem localmente. Isso torna a primeira execução mais demorada, mas as execuções seguintes ficam mais rápidas.
na_codes <- c("", "NA", "NULL", "PrivacySuppressed")
institution_raw <- readr::read_csv(
institution_csv,
na = na_codes,
show_col_types = FALSE
)
field_raw <- readr::read_csv(
field_csv,
na = na_codes,
show_col_types = FALSE
)
institution <- institution_raw |>
janitor::clean_names() |>
select(any_of(c(
"unitid", "instnm", "city", "stabbr", "region", "control", "locale", "highdeg", "preddeg",
"adm_rate", "sat_avg", "ugds", "costt4_a", "tuitionfee_in", "tuitionfee_out",
"avgfacsal", "pftfac", "pctpell", "c150_4", "ret_ft4", "debt_mdn",
"md_earn_wne_p10", "rpy_3yr_rt", "curroper", "openadmp"
))) |>
mutate(
across(
c(adm_rate, sat_avg, ugds, costt4_a, tuitionfee_in, tuitionfee_out,
avgfacsal, pftfac, pctpell, c150_4, ret_ft4, debt_mdn,
md_earn_wne_p10, rpy_3yr_rt),
~ readr::parse_number(as.character(.x))
),
tipo_controle = case_when(
control == 1 ~ "Publica",
control == 2 ~ "Privada sem fins lucrativos",
control == 3 ~ "Privada com fins lucrativos",
TRUE ~ "Nao informado"
),
regiao = case_when(
region == 1 ~ "Nova Inglaterra",
region == 2 ~ "Meio-Leste",
region == 3 ~ "Grandes Lagos",
region == 4 ~ "Plains",
region == 5 ~ "Sudeste",
region == 6 ~ "Sudoeste",
region == 7 ~ "Montanhas Rochosas",
region == 8 ~ "Extremo Oeste",
region == 9 ~ "Territorios/EUA exterior",
TRUE ~ "Nao informado"
),
nivel_predominante = case_when(
preddeg == 1 ~ "Certificado",
preddeg == 2 ~ "Associado",
preddeg == 3 ~ "Bacharelado",
preddeg == 4 ~ "Pos-graduacao",
TRUE ~ "Outro/nao classificado"
),
porte = case_when(
is.na(ugds) ~ "Nao informado",
ugds < 1000 ~ "Pequeno",
ugds < 5000 ~ "Medio",
ugds < 15000 ~ "Grande",
TRUE ~ "Muito grande"
),
seletividade = case_when(
is.na(adm_rate) ~ "Nao informada",
adm_rate < 0.30 ~ "Alta seletividade",
adm_rate < 0.70 ~ "Seletividade moderada",
TRUE ~ "Baixa seletividade"
),
custo_liquido_aprox = coalesce(costt4_a, tuitionfee_in),
renda_dez_anos = md_earn_wne_p10,
razao_renda_custo = renda_dez_anos / custo_liquido_aprox,
taxa_conclusao = c150_4,
taxa_retencao = ret_ft4,
taxa_pagamento_emprestimo = rpy_3yr_rt
) |>
filter(curroper == 1, !is.na(tipo_controle), !is.na(ugds), ugds > 0)
field <- field_raw |>
janitor::clean_names() |>
select(any_of(c(
"unitid", "instnm", "cipcode", "cipdesc", "credlev", "creddesc",
"debtmedian", "debt_all_stgp_any_mdn", "earn_mdn_hi_1yr", "earn_mdn_1yr",
"count_ed", "ipedscount1", "count_nwne_1yr", "earn_count_nwne_hi_1yr"
))) |>
rename(
debtmedian = any_of(c("debtmedian", "debt_all_stgp_any_mdn")),
count_ed = any_of(c("count_ed", "ipedscount1")),
count_nwne_1yr = any_of(c("count_nwne_1yr", "earn_count_nwne_hi_1yr"))
) |>
mutate(earn_mdn_hi_1yr = coalesce(earn_mdn_hi_1yr, earn_mdn_1yr)) |>
mutate(
across(any_of(c("debtmedian", "earn_mdn_hi_1yr", "count_ed", "count_nwne_1yr")),
~ readr::parse_number(as.character(.x))),
cipdesc = str_to_title(cipdesc),
creddesc = str_to_sentence(creddesc),
retorno_curto_prazo = earn_mdn_hi_1yr / debtmedian
) |>
filter(!is.na(unitid), !is.na(cipdesc))
field_summary <- field |>
group_by(unitid) |>
summarise(
n_areas_estudo = n_distinct(cipdesc),
divida_mediana_area = median(debtmedian, na.rm = TRUE),
ganho_mediano_1ano_area = median(earn_mdn_hi_1yr, na.rm = TRUE),
retorno_mediano_area = median(retorno_curto_prazo, na.rm = TRUE),
.groups = "drop"
) |>
mutate(across(where(is.numeric), ~ if_else(is.infinite(.x), NA_real_, .x)))
college <- institution |>
left_join(field_summary, by = "unitid") |>
mutate(
classificacao_resultado = case_when(
taxa_conclusao >= median(taxa_conclusao, na.rm = TRUE) &
razao_renda_custo >= median(razao_renda_custo, na.rm = TRUE) ~ "Conclusao e retorno acima da mediana",
taxa_conclusao >= median(taxa_conclusao, na.rm = TRUE) ~ "Conclusao acima da mediana",
razao_renda_custo >= median(razao_renda_custo, na.rm = TRUE) ~ "Retorno acima da mediana",
TRUE ~ "Abaixo das medianas analisadas"
)
)As principais etapas de limpeza foram necessárias porque a base original é muito ampla e contém códigos que dificultam a análise direta. Foram selecionadas variáveis ligadas ao problema de pesquisa, os nomes foram padronizados, variáveis numéricas foram convertidas corretamente, códigos de tipo de instituição e região foram traduzidos para categorias textuais, instituições inativas foram removidas e novas variáveis foram criadas.
As variáveis criadas foram:
tipo_controle: traduz se a instituição é pública,
privada sem fins lucrativos ou privada com fins lucrativos.porte: classifica o tamanho da instituição pelo número
de estudantes de graduação.seletividade: classifica a taxa de admissão em alta,
moderada ou baixa seletividade.custo_liquido_aprox: aproxima o custo principal usando
custo acadêmico anual ou mensalidade interna disponível.razao_renda_custo: compara renda mediana após 10 anos
com custo aproximado.n_areas_estudo, divida_mediana_area e
ganho_mediano_1ano_area: resumem a tabela por áreas de
estudo e são unidos à base institucional.| Base | Linhas | Colunas |
|---|---|---|
| Institucional original | 6,322 | 3,308 |
| Areas de estudo original | 227,980 | 178 |
| Base final limpa e unida | 5,481 | 41 |
A base final atende ao requisito de ter mais de 5 mil linhas e mais de 10 colunas após limpeza e união dos dados. Para evitar imprimir uma tabela muito grande, abaixo está apenas uma amostra das variáveis centrais.
| Indicador | Valor |
|---|---|
| Instituicoes analisadas | 5,481 |
| Estados/territorios | 59 |
| Matricula mediana | 564 |
| Taxa mediana de admissao | 78.0% |
| Taxa mediana de conclusao | 52.3% |
| Taxa mediana de retencao | 75.7% |
| Custo mediano aproximado | US$24,902 |
| Divida mediana | US$9,500 |
| Renda mediana apos 10 anos | US$40,740 |
| Razao renda/custo mediana | 2 |
O conjunto limpo combina variáveis categóricas
(tipo_controle, regiao, porte,
seletividade), variáveis numéricas (ugds,
custo_liquido_aprox, debt_mdn,
renda_dez_anos) e variáveis proporcionais
(adm_rate, taxa_conclusao,
taxa_retencao, taxa_pagamento_emprestimo).
Essa diversidade permite investigar o problema por vários ângulos, sem
depender de uma única medida de desempenho.
| Tipo de instituicao | Quantidade | Percentual |
|---|---|---|
| Privada com fins lucrativos | 2055 | 37.5% |
| Publica | 1888 | 34.4% |
| Privada sem fins lucrativos | 1538 | 28.1% |
g_perfil <- perfil |>
ggplot(aes(x = reorder(tipo_controle, n), y = n, fill = tipo_controle)) +
geom_col(width = 0.72, show.legend = FALSE) +
coord_flip() +
scale_y_continuous(labels = scales::comma) +
labs(
title = "Distribuicao das instituicoes por tipo de controle",
subtitle = "Instituicoes publicas, privadas sem fins lucrativos e privadas com fins lucrativos aparecem em proporcoes distintas",
x = NULL,
y = "Numero de instituicoes"
)
g_perfilO primeiro resultado mostra que a estrutura do ensino superior analisado não é homogênea. Existem instituições com modelos de governança diferentes, e isso justifica comparar os indicadores por tipo de controle, em vez de tratar todas as instituições como se pertencessem ao mesmo grupo.
resumo_controle <- college |>
group_by(tipo_controle) |>
summarise(
instituicoes = n(),
matricula_mediana = median(ugds, na.rm = TRUE),
custo_mediano = median(custo_liquido_aprox, na.rm = TRUE),
divida_mediana = median(debt_mdn, na.rm = TRUE),
renda_mediana_10anos = median(renda_dez_anos, na.rm = TRUE),
conclusao_mediana = median(taxa_conclusao, na.rm = TRUE),
retencao_mediana = median(taxa_retencao, na.rm = TRUE),
razao_renda_custo_mediana = median(razao_renda_custo, na.rm = TRUE),
.groups = "drop"
) |>
arrange(desc(renda_mediana_10anos))
resumo_controle |>
mutate(
matricula_mediana = scales::comma(matricula_mediana, accuracy = 1),
across(c(custo_mediano, divida_mediana, renda_mediana_10anos), ~ scales::dollar(.x, prefix = "US$", accuracy = 1)),
across(c(conclusao_mediana, retencao_mediana), ~ scales::percent(.x, accuracy = 0.1)),
razao_renda_custo_mediana = round(razao_renda_custo_mediana, 2)
) |>
knitr::kable(col.names = c(
"Tipo", "Instituicoes", "Matricula mediana", "Custo mediano", "Divida mediana",
"Renda mediana 10 anos", "Conclusao mediana", "Retencao mediana", "Renda/custo"
)) |>
kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))| Tipo | Instituicoes | Matricula mediana | Custo mediano | Divida mediana | Renda mediana 10 anos | Conclusao mediana | Retencao mediana | Renda/custo |
|---|---|---|---|---|---|---|---|---|
| Privada sem fins lucrativos | 1538 | 808 | US$44,211 | US$16,000 | US$53,187 | 57.4% | 77.0% | 1.12 |
| Publica | 1888 | 2,630 | US$17,730 | US$8,730 | US$42,382 | 46.2% | 75.6% | 2.41 |
| Privada com fins lucrativos | 2055 | 149 | US$30,868 | US$8,265 | US$29,833 | 50.0% | 66.7% | 1.33 |
plot_data <- college |>
filter(
!is.na(custo_liquido_aprox), !is.na(renda_dez_anos),
custo_liquido_aprox > 0, renda_dez_anos > 0
) |>
mutate(
texto = paste0(
"Instituicao: ", instnm,
"<br>Tipo: ", tipo_controle,
"<br>Estado: ", stabbr,
"<br>Custo aprox.: ", scales::dollar(custo_liquido_aprox, prefix = "US$"),
"<br>Renda 10 anos: ", scales::dollar(renda_dez_anos, prefix = "US$"),
"<br>Conclusao: ", scales::percent(taxa_conclusao, accuracy = 0.1)
)
)
g_custo_renda <- plot_data |>
ggplot(aes(
x = custo_liquido_aprox,
y = renda_dez_anos,
color = tipo_controle,
size = ugds,
text = texto
)) +
geom_point(alpha = 0.55) +
scale_x_continuous(labels = scales::dollar_format(prefix = "US$")) +
scale_y_continuous(labels = scales::dollar_format(prefix = "US$")) +
scale_size_continuous(labels = scales::comma, range = c(1.5, 9)) +
labs(
title = "Custo anual aproximado e renda mediana apos 10 anos",
subtitle = "Cada ponto representa uma instituicao; o tamanho indica matricula de graduacao",
x = "Custo anual aproximado",
y = "Renda mediana apos 10 anos",
color = "Tipo de instituicao",
size = "Matricula"
)
plotly::ggplotly(g_custo_renda, tooltip = "text")O gráfico interativo permite observar que custo maior não significa automaticamente maior renda posterior. Existem instituições caras com renda futura moderada e instituições com custo menor que apresentam renda posterior competitiva. Esse é um ponto central para potenciais estudantes: o preço isolado pode ser uma medida enganosa de qualidade ou retorno.
g_retencao <- college |>
filter(!is.na(taxa_conclusao), !is.na(taxa_retencao)) |>
ggplot(aes(x = taxa_retencao, y = taxa_conclusao, color = tipo_controle)) +
geom_point(alpha = 0.45) +
geom_smooth(method = "lm", se = FALSE) +
scale_x_continuous(labels = scales::percent) +
scale_y_continuous(labels = scales::percent) +
labs(
title = "Instituicoes que retêm estudantes tendem a concluir mais",
subtitle = "A relacao positiva sugere que permanencia no primeiro ano e conclusao estao conectadas",
x = "Taxa de retencao em tempo integral",
y = "Taxa de conclusao em 150% do tempo previsto",
color = "Tipo de instituicao"
)
g_retencaoA retenção aparece como um indicador de alerta. Instituições com baixa retenção tendem a apresentar baixa conclusão. Para estudantes e famílias, isso sugere que a decisão de matrícula deve considerar não apenas a entrada, mas também a capacidade da instituição de manter o estudante até a conclusão.
seletividade_resumo <- college |>
filter(seletividade != "Nao informada") |>
group_by(seletividade, tipo_controle) |>
summarise(
instituicoes = n(),
renda_mediana_10anos = median(renda_dez_anos, na.rm = TRUE),
conclusao_mediana = median(taxa_conclusao, na.rm = TRUE),
custo_mediano = median(custo_liquido_aprox, na.rm = TRUE),
.groups = "drop"
)
g_seletividade <- seletividade_resumo |>
ggplot(aes(x = seletividade, y = renda_mediana_10anos, fill = tipo_controle)) +
geom_col(position = position_dodge(width = 0.75), width = 0.68) +
scale_y_continuous(labels = scales::dollar_format(prefix = "US$")) +
labs(
title = "Renda posterior por seletividade e tipo de instituicao",
subtitle = "A seletividade pode sinalizar diferencas de perfil institucional, mas nao deve ser lida isoladamente",
x = "Classe de seletividade",
y = "Renda mediana apos 10 anos",
fill = "Tipo"
) +
theme(axis.text.x = element_text(angle = 15, hjust = 1))
g_seletividadeInstituições mais seletivas tendem a apresentar renda posterior maior, mas essa relação precisa ser interpretada com cautela. Parte do resultado pode refletir diferenças anteriores dos estudantes admitidos, localização, reputação institucional e áreas de estudo oferecidas. Ainda assim, a seletividade se mostra útil como variável de segmentação na análise exploratória.
regiao_resumo <- college |>
filter(!is.na(razao_renda_custo), is.finite(razao_renda_custo)) |>
group_by(regiao) |>
summarise(
instituicoes = n(),
renda_custo_mediana = median(razao_renda_custo, na.rm = TRUE),
custo_mediano = median(custo_liquido_aprox, na.rm = TRUE),
renda_mediana = median(renda_dez_anos, na.rm = TRUE),
.groups = "drop"
) |>
filter(instituicoes >= 20) |>
arrange(desc(renda_custo_mediana))
regiao_resumo |>
mutate(
renda_custo_mediana = round(renda_custo_mediana, 2),
across(c(custo_mediano, renda_mediana), ~ scales::dollar(.x, prefix = "US$", accuracy = 1))
) |>
knitr::kable(col.names = c("Regiao", "Instituicoes", "Renda/custo mediana", "Custo mediano", "Renda mediana")) |>
kableExtra::kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))| Regiao | Instituicoes | Renda/custo mediana | Custo mediano | Renda mediana |
|---|---|---|---|---|
| Extremo Oeste | 371 | 2.15 | US$21,772 | US$48,143 |
| Sudoeste | 277 | 2.14 | US$21,064 | US$42,375 |
| Montanhas Rochosas | 103 | 2.12 | US$21,526 | US$44,511 |
| Plains | 313 | 1.98 | US$25,172 | US$48,179 |
| Grandes Lagos | 452 | 1.81 | US$28,016 | US$47,858 |
| Sudeste | 818 | 1.77 | US$24,756 | US$40,280 |
| Territorios/EUA exterior | 89 | 1.71 | US$14,487 | US$24,632 |
| Meio-Leste | 494 | 1.61 | US$30,414 | US$54,516 |
| Nova Inglaterra | 184 | 1.33 | US$42,258 | US$55,213 |
regiao_resumo |>
ggplot(aes(x = reorder(regiao, renda_custo_mediana), y = renda_custo_mediana)) +
geom_col(fill = "#2c7fb8", width = 0.72) +
coord_flip() +
labs(
title = "Razao entre renda apos 10 anos e custo por regiao",
subtitle = "Valores maiores indicam renda posterior mais alta em relacao ao custo anual aproximado",
x = NULL,
y = "Renda/custo mediana"
)A comparação regional adiciona uma camada importante: o retorno financeiro não depende apenas da instituição, mas também do contexto econômico. Regiões com maior renda posterior podem refletir mercados de trabalho mais fortes, maior concentração de setores de alta remuneração ou composição diferente de cursos.
area_resumo <- field |>
filter(!is.na(debtmedian), !is.na(earn_mdn_hi_1yr), debtmedian > 0, earn_mdn_hi_1yr > 0) |>
group_by(cipdesc) |>
summarise(
registros = n(),
divida_mediana = median(debtmedian, na.rm = TRUE),
ganho_mediano_1ano = median(earn_mdn_hi_1yr, na.rm = TRUE),
retorno_curto_prazo = median(retorno_curto_prazo, na.rm = TRUE),
.groups = "drop"
) |>
filter(registros >= 30) |>
arrange(desc(retorno_curto_prazo))
area_resumo |>
slice_head(n = 15) |>
mutate(
divida_mediana = scales::dollar(divida_mediana, prefix = "US$", accuracy = 1),
ganho_mediano_1ano = scales::dollar(ganho_mediano_1ano, prefix = "US$", accuracy = 1),
retorno_curto_prazo = round(retorno_curto_prazo, 2)
) |>
DT::datatable(
rownames = FALSE,
options = list(pageLength = 10, scrollX = TRUE),
caption = htmltools::tags$caption("Areas de estudo com maior ganho inicial em relacao a divida mediana")
)top_areas <- area_resumo |>
slice_head(n = 12)
g_areas <- top_areas |>
ggplot(aes(x = reorder(cipdesc, retorno_curto_prazo), y = retorno_curto_prazo, fill = ganho_mediano_1ano)) +
geom_col(width = 0.72) +
coord_flip() +
scale_fill_viridis_c(labels = scales::dollar_format(prefix = "US$")) +
labs(
title = "Areas de estudo com melhor retorno financeiro inicial",
subtitle = "Retorno calculado como ganho mediano um ano apos conclusao dividido pela divida mediana",
x = NULL,
y = "Ganho inicial / divida mediana",
fill = "Ganho mediano"
)
g_areasA análise por área de estudo revela uma informação que a base institucional sozinha não mostra. O retorno pode variar fortemente conforme o campo de formação. Isso reforça que a escolha educacional envolve pelo menos duas decisões: onde estudar e o que estudar.
ranking <- college |>
filter(
!is.na(taxa_conclusao), !is.na(razao_renda_custo), !is.na(renda_dez_anos),
ugds >= 500, custo_liquido_aprox > 0
) |>
mutate(
score_conclusao = percent_rank(taxa_conclusao),
score_retorno = percent_rank(razao_renda_custo),
score_retencao = percent_rank(taxa_retencao),
score_final = 0.45 * score_conclusao + 0.40 * score_retorno + 0.15 * score_retencao
) |>
arrange(desc(score_final)) |>
select(
Instituicao = instnm,
Estado = stabbr,
Tipo = tipo_controle,
Porte = porte,
`Taxa de conclusao` = taxa_conclusao,
`Taxa de retencao` = taxa_retencao,
`Custo aproximado` = custo_liquido_aprox,
`Renda 10 anos` = renda_dez_anos,
`Renda/custo` = razao_renda_custo,
`Score final` = score_final
)
ranking |>
slice_head(n = 25) |>
DT::datatable(
rownames = FALSE,
filter = "top",
options = list(pageLength = 10, scrollX = TRUE),
caption = htmltools::tags$caption("Ranking exploratorio: conclusao, retencao e retorno financeiro")
) |>
DT::formatPercentage(c("Taxa de conclusao", "Taxa de retencao", "Score final"), digits = 1) |>
DT::formatCurrency(c("Custo aproximado", "Renda 10 anos"), currency = "US$", digits = 0) |>
DT::formatRound("Renda/custo", digits = 2)O ranking é uma construção exploratória e não deve ser interpretado como uma lista definitiva de melhores instituições. Ele combina três critérios: conclusão, retorno financeiro e retenção. O objetivo é demonstrar como variáveis podem ser criadas para transformar dados brutos em informação comparável. A ponderação escolhida dá maior peso à conclusão e ao retorno, pois esses dois elementos se conectam diretamente à pergunta do projeto.
Este projeto investigou como características das instituições de ensino superior se relacionam com resultados acadêmicos e financeiros dos estudantes. A análise foi construída a partir de dados públicos do College Scorecard, combinando informações institucionais com informações por área de estudo. O processo incluiu importação direta da web, limpeza, padronização de tipos, tratamento de valores ausentes, criação de variáveis e junção de bases.
Os principais insights encontrados foram:
Para potenciais estudantes e famílias, a implicação prática é clara: a decisão educacional deve considerar uma combinação de fatores. Uma instituição pode ser barata, mas ter baixa conclusão; outra pode ser cara, mas gerar renda posterior elevada; uma terceira pode ter bom resultado médio, mas oferecer cursos com retornos muito diferentes. Para gestores e formuladores de políticas, os dados indicam que permanência, conclusão e endividamento devem ser monitorados conjuntamente.
A análise possui limitações. Primeiro, ela é descritiva e não estabelece causalidade. Instituições com maior renda posterior podem atender estudantes com perfil socioeconômico diferente, localização mais favorável ou maior concentração em áreas de alta remuneração. Segundo, alguns indicadores possuem valores ausentes ou suprimidos por privacidade, o que reduz a comparabilidade. Terceiro, o custo usado é uma aproximação e pode não representar exatamente o custo real enfrentado por cada estudante.
Em trabalhos futuros, seria possível melhorar a análise com modelos estatísticos controlando por região, porte, tipo de instituição e perfil dos estudantes. Também seria interessante comparar vários anos para avaliar tendências temporais, incluir variáveis de composição socioeconômica e construir uma aplicação Shiny para permitir que usuários filtrem instituições de acordo com seus próprios critérios.
| Requisito | Como foi atendido |
|---|---|
| Dados online e gratuitos | Dados baixados diretamente do portal oficial College Scorecard. |
| Mais de 5 mil linhas e mais de 10 colunas | A base final limpa possui milhares de instituicoes e dezenas de variaveis. |
| Tipos variados de dados | Foram usadas variaveis numericas, categoricas, proporcionais e identificadores textuais. |
| Dados com necessidade de tratamento | Foram tratados NAs, codigos especiais, tipos numericos importados como texto e categorias codificadas. |
| Juncao de tabelas | Dados institucionais foram unidos a dados por area de estudo usando UNITID. |
| Variaveis criadas | Foram criadas variaveis como porte, seletividade, razao renda/custo, retorno por area e score final. |
| Graficos e tabelas | O relatorio inclui graficos ggplot2, grafico interativo plotly e tabelas DT. |
| Narrativa e conclusoes | Cada etapa inclui interpretacao textual e conclusao conectada ao problema inicial. |