# ===================================================================
# SETUP
# ===================================================================
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(here)
## here() starts at C:/Users/Rafael/OneDrive/CAPES Quadrienal 2025
library(glue)
# ===================================================================
# LOAD DATA
# ===================================================================
spine <- read_csv(here("data", "planilhao", "spine.csv"))
## Rows: 547 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (15): Cod PPG, Nome PPG, IES Principal Sigla, IES Principal Nome, IES da...
## dbl (7): Ano base, PPG Ano Início, DPs, Colaboradores, Visitantes, Disserta...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
output <- read_csv(here("data", "planilhao", "producao_detalhada.csv"))
## Rows: 113940 Columns: 19
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (8): Cod PPG, Titulo da Produção, Tipo, Subtipo, Estrato, ISSN_ISBN, So...
## dbl (11): Ano base, Permanente, Colaborador, Visitante, Total de Discentes, ...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
docente <- read_csv(here("data", "planilhao", "docente2.csv"))
## Rows: 12522 Columns: 31
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (10): Cod PPG, Nome do docente, Sexo, Faixa Etária, Área de Conhecimento...
## dbl (21): Ano base, ID_Docente, Ano Titulação, Carga horária semanal no prog...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
discente <- read_csv(here("data", "planilhao", "discente_full.csv"))
## Rows: 37584 Columns: 7
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): Cod PPG, Discente, Sexo, Situação Mestrado, Situação Doutorado
## dbl (2): Ano base, Identificador
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
egresso <- read_csv(here("data", "planilhao", "egresso.csv"))
## Rows: 24003 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (4): Cod PPG, Egresso, Situação Mestrado, Situação Doutorado
## dbl (2): Ano Titulação Mestrado, Ano Titulação Doutorado
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
destaques <- read_csv(here("data", "destaques", "destaques2.csv"))
## Rows: 11174 Columns: 10
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (10): EVENTO, TIPO EVENTO, IES, Cod PPG, Nome PPG, NIVEL, NOME DO EGRESS...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
malafaia <- read_csv(here("data", "planilhao", "malafaia.csv")) # retracted articles
## Rows: 47 Columns: 1
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Titulo da Produção
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
nomes_var <- read_csv(here("data", "planilhao", "nomes_var.csv"))
## Rows: 95 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): var, nome
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# ===================================================================
# WEIGHTS
# ===================================================================
weights <- tibble::tribble(
~Estrato, ~Weight,
# Artigos
"A1", 1.00, "A2", 0.85, "A3", 0.70, "A4", 0.60,
"B1", 0.50, "B2", 0.35, "B3", 0.20, "B4", 0.10,
# Livros
"L1", 1.00, "L2", 0.80, "L3", 0.60, "L4", 0.40, "L5", 0.20,
# Produtos técnicos (PTT)
"T1", 1.00, "T2", 0.80, "T3", 0.60, "T4", 0.40, "T5", 0.20
)
w <- as.list(setNames(weights$Weight, tolower(weights$Estrato)))
conceitos <- tibble::tribble(
~CONCEITO, ~Weight,
"Muito bom", 10,
"Bom", 7.5,
"Regular", 5,
"Fraco", 2.5,
"Insuficiente", 0,
"Não aderente", 0)
# ===================================================================
# DATA PREPARATION
# ===================================================================
programa <- spine |> select(`Ano base`, `Cod PPG`, `Nome PPG`,
`IES Principal Sigla`, `Região`, Modalidade,
Nota, Nível, `Ano de Início`, `Situação`) |> distinct()
ppg_key <- programa |> distinct(`Cod PPG`)
docente_cols_to_transform <- c(
"Responsável por Projeto com Participação Discente",
"Responsável com financiamento e participação discente",
"Turmas ministradas - Responsável",
"Turmas ministradas - Participante",
"Atividades na Graduação",
"Permanente em outros PPGs"
)
cols_to_drop <- c(
"Orientações em andamento - MP",
"Orientações em andamento - DP",
"Orientações concluídas - MP",
"Orientações concluídas - DP"
)
dp <- docente |>
filter(Categoria == "PERMANENTE") |>
mutate(
# Converte colunas numéricas para flags booleanos (VERDADEIRO/FALSO)
across(
any_of(docente_cols_to_transform),
~ replace_na(as.numeric(.x), 0) > 0
),
# Converte colunas de texto CNPq para flags booleanos
# Converte NAs e células vazias para FALSO
across(
contains("CNPq"),
~ !is.na(.x) & .x != ""
),
# Processa status de permanência no quadriênio
`Permanente ao longo do quadriênio` =
str_to_upper(trimws(`Permanente ao longo do quadriênio`)) == "SIM",
# Combina orientações em andamento (Mestrado + Mestrado Profissional)
`Orientações em andamento - ME` =
coalesce(`Orientações em andamento - ME`, 0) +
coalesce(`Orientações em andamento - MP`, 0),
# Combina orientações em andamento (Doutorado + Doutorado Profissional)
`Orientações em andamento - DO` =
coalesce(`Orientações em andamento - DO`, 0) +
coalesce(`Orientações em andamento - DP`, 0),
# Combina orientações concluídas (Mestrado + Mestrado Profissional)
`Orientações concluídas - ME` =
coalesce(`Orientações concluídas - ME`, 0) +
coalesce(`Orientações concluídas - MP`, 0),
# Combina orientações concluídas (Doutorado + Doutorado Profissional)
`Orientações concluídas - DO` =
coalesce(`Orientações concluídas - DO`, 0) +
coalesce(`Orientações concluídas - DP`, 0),
# NOVAS VARIÁVEIS
# Docente não possui orientações
`Não orientou` = (
`Orientações em andamento - ME` +
`Orientações em andamento - DO` +
`Orientações concluídas - ME` +
`Orientações concluídas - DO`
) == 0,
# Docente ministrou turmas no PPG
`Turmas ministradas` =
`Turmas ministradas - Responsável` | `Turmas ministradas - Participante`,
# Docente possui bolsa CNPq
`Bolsista CNPq` =
`Bolsa Produtividade - Pesquisa CNPq` |
`Bolsa Produtividade - Desen. Tec. e Extensão Inovadora CNPq`,
# Docente é exclusivo (não é permanente em outros PPGs)
Exclusivo = !`Permanente em outros PPGs`
) |>
# Renomeia coluna principal de identificação
rename(Docente = `Nome do docente`) |>
# Remove colunas desnecessárias
select(-any_of(cols_to_drop))
egresso <- egresso |>
mutate(
# Substitui valores ausentes por "NÃO TITULADO" nas colunas de situação
across(
contains("Situação"),
~ replace_na(.x, "NÃO TITULADO")
),
# Cria flags booleanos para titulação por nível
`Titulado Mestrado` = `Situação Mestrado` == "TITULADO",
`Titulado Doutorado` = `Situação Doutorado` == "TITULADO",
# Calcula o ano da titulação mais recente entre mestrado e doutorado
`Ano da Titulação mais Recente` =
pmax(`Ano Titulação Mestrado`, `Ano Titulação Doutorado`, na.rm = TRUE)
) |>
# Remove colunas de situação originais (já processadas)
select(-`Situação Mestrado`, -`Situação Doutorado`)
# Processamento dos dados de DISCENTES
discente <- discente |>
mutate(
# Substitui valores ausentes por "NÃO MATRICULADO" nas colunas de situação
across(
contains("Situação"),
~ replace_na(.x, "NÃO MATRICULADO")
),
# Cria flags booleanos para matrícula por nível
# Prioriza doutorado sobre mestrado (discente pode estar em ambos)
`Matriculado Doutorado` = `Situação Doutorado` == "MATRICULADO",
`Matriculado Mestrado` = `Situação Mestrado` == "MATRICULADO" &
!`Matriculado Doutorado`
) |>
# Mantém apenas discentes atualmente matriculados em algum nível
filter(`Matriculado Doutorado` | `Matriculado Mestrado`)
output <- output |>
filter(str_detect(Estrato, "^(A[1-4]|B[1-4]|L[1-5]|T[1-5])$"),
Permanente > 0,
!`Titulo da Produção` %in% malafaia$`Titulo da Produção`) |>
select(-c(Permanente, Colaborador, Visitante, `Total de Discentes`, Doutorado, `Doutorado Profissional`,
Mestrado, `Mestrado Profissional`, `Egresso Acima de 5 anos`, `Egresso Até 5 anos`)
)
# Processamento dos AUTORES das produções científicas
output_autor <- output |>
# Separa múltiplos autores em linhas individuais
separate_rows(Autores, sep = "\\|") |>
# Remove espaços extras dos nomes dos autores
mutate(Autores = str_squish(Autores)) |>
# Separa o nome e vínculo do autor
separate(
Autores,
into = c("Nome", "group"),
sep = "\\(",
fill = "right"
) |>
mutate(
# Limpa e padroniza o vínculo do autor
group = str_squish(str_remove(group, "\\)$")),
Nome = str_squish(Nome),
# Cria chave para o vínculo do autor
group_key = case_when(
str_detect(tolower(group), "discente[ _]mestrado") ~ "discente_mestrado",
str_detect(tolower(group), "discente[ _]doutorado") ~ "discente_doutorado",
str_detect(tolower(group), "egresso") ~ "egresso",
str_detect(tolower(group), "docente permanente") ~ "dp"
),
# Cria identificador único do autor (nome + vínculo + programa)
author_key = str_c(Nome, "_", group_key, "_", `Cod PPG`)
) |>
# Remove registros onde não foi possível identificar o tipo de vínculo (por exemplo, autores externos)
filter(!is.na(group_key))
# ===================================================================
# ANÁLISE DOS DADOS
# ===================================================================
# AUTORES POR ESTRATO DE PERIÓDICO =====================================
# Função para filtrar autores por estrato de publicação
filtro_autor_por_estrato <- function(publication_list = output_autor, pattern) {
publication_list |>
filter(str_detect(Estrato, pattern)) |>
distinct(`Cod PPG`, Nome, group_key, author_key)
}
# Autores com publicações em periódicos A1 e A2 (estratos superiores)
author_A1_A2 <- filtro_autor_por_estrato(pattern = "^(A1|A2)$")
# Autores com publicações em periódicos estrato A (A1, A2, A3, A4)
author_A <- filtro_autor_por_estrato(pattern = "^A[1-4]$")
# Autores com publicações em periódicos estratos A e B (A1-A4, B1-B4)
author_AB <- filtro_autor_por_estrato(pattern = "^[AB][1-4]$")
# DISCENTES E EGRESSOS POR NÍVEL ACADÊMICO =============================
# Critérios de inclusão:
# - Discentes: matriculados no último ano do quadriênio (2024)
# - Egressos: titulados nos últimos cinco anos (2020-2024)
# Discentes de MESTRADO matriculados em 2024
students_master <- discente |>
filter(`Ano base` == 2024, `Matriculado Mestrado`) |>
mutate(group = "discente_mestrado") |>
select(`Cod PPG`, Nome = Discente, group) |>
distinct()
# Discentes de DOUTORADO matriculados em 2024
students_phd <- discente |>
filter(`Ano base` == 2024, `Matriculado Doutorado`) |>
mutate(group = "discente_doutorado") |>
select(`Cod PPG`, Nome = Discente, group) |>
distinct()
# Egressos de MESTRADO titulados entre 2020-2024
graduates_master <- egresso |>
filter(`Ano da Titulação mais Recente` >= 2020, `Titulado Mestrado`) |>
mutate(group = "egresso_mestrado") |>
select(`Cod PPG`, Nome = Egresso, group) |>
distinct()
# Egressos de DOUTORADO titulados entre 2020-2024
graduates_phd <- egresso |>
filter(`Ano da Titulação mais Recente` >= 2020, `Titulado Doutorado`) |>
mutate(group = "egresso_doutorado") |>
select(`Cod PPG`, Nome = Egresso, group) |>
distinct()
# ANÁLISE DE DISCENTES E EGRESSOS POR ESTRATO DE PERIÓDICO ===============
# Consolida todos os discentes e egressos elegíveis para análise
# Critérios: Discentes matriculados em 2024 OU Egressos titulados 2020-2024
students_graduates <- bind_rows(
students_master,
students_phd,
graduates_master,
graduates_phd
) |>
# Padroniza as chaves de grupo
mutate(group_key = case_when(
str_detect(tolower(group), "discente[ _]mestrado") ~ "discente_mestrado",
str_detect(tolower(group), "discente[ _]doutorado") ~ "discente_doutorado",
str_detect(tolower(group), "egresso") ~ "egresso"
),
author_key = str_c(Nome, "_", group_key, "_", `Cod PPG`)
) |>
# Verifica se cada discente/egresso possui publicações nos diferentes estratos
mutate(
author_A1_A2 = author_key %in% author_A1_A2$author_key,
author_A = author_key %in% author_A$author_key,
author_AB = author_key %in% author_AB$author_key
) |>
# Calcula estatísticas por PPG e grupo (discente mestrado, discente doutorado e egresso)
group_by(`Cod PPG`, group) |>
summarize(
total = n(), # Total de indivíduos no grupo
estrato_A1_A2 = sum(author_A1_A2), # Quantos publicaram em A1/A2
estrato_A = sum(author_A), # Quantos publicaram em A
estrato_AB = sum(author_AB), # Quantos publicaram em A ou B
.groups = 'drop'
) |>
# Transforma dados de formato longo para formato amplo (Excel)
# Cada métrica (total, A1_A2, A, AB) vira uma coluna separada por grupo
pivot_longer(
cols = c("total", "estrato_A1_A2", "estrato_A", "estrato_AB"),
names_to = "metrica",
values_to = "count"
) |>
# Cria nomes de colunas combinando grupo e métrica
mutate(group_metrica = paste0(group, "_", metrica)) |>
select(-group, -metrica) |>
# Converte para formato final: uma linha por PPG, colunas para cada combinação
pivot_wider(
names_from = group_metrica,
values_from = count,
values_fill = 0
) |>
# Adiciona informações dos PPGs e preenche valores ausentes
right_join(ppg_key, by = "Cod PPG") |>
mutate(across(everything(), ~ replace_na(.x, 0)))
# PRODUÇÃO QUALIFICADA DE DISCENTES E EGRESSOS ============================
# Critérios de qualificação da produção:
# - Artigos: estratos A (A1-A4) ou B (B1-B4)
# - Livros : estratos L (L1-L5)
# - Produtos Técnicos e Tecnológicos (PTT): estratos T (T1-T5)
# Consolida produção de discentes e egressos durante o quadriênio
students_graduates_output <- bind_rows(
# Todos os discentes do período
discente |> select(`Cod PPG`, Nome = Discente),
# Todos os egressos do período
egresso |> select(`Cod PPG`, Nome = Egresso)
) |>
# Remove duplicatas (mesmo indivíduo pode ser discente e egresso)
distinct() |>
# Conecta com as produções dos discentes/egressos
inner_join(
output_autor |>
filter(str_detect(group_key, "discente|egresso")),
by = c("Cod PPG", "Nome")
) |>
# Uma produção conta apenas uma vez por programa
distinct(`Cod PPG`, `Titulo da Produção`, Estrato) |>
# Conta produções por PPG e estrato
count(`Cod PPG`, Estrato) |>
# Completa combinações ausentes (PPG sem produção em determinado estrato) com 0
complete(`Cod PPG`, Estrato, fill = list(n = 0))
# INDICADOR DE PRODUÇÃO DISCENTE/EGRESSO (INDProd) ========================
# Fórmula: Produção qualificada ponderada / Total ponderado de discentes (2024) e egressos (2020-2024)
#
# Ponderação do denominador:
# - 1 discente/egresso de mestrado = peso 1
# - 1 discente/egresso de doutorado = peso 2
indprod_disc <- students_graduates_output |>
# Adiciona pesos por estrato de produção
left_join(weights, by = "Estrato") |>
# Calcula produção ponderada (quantidade × peso do estrato)
mutate(weighted_output = n * Weight) |>
# Soma produção ponderada total por PPG (numerador do INDProd discente/egresso)
count(
`Cod PPG`,
wt = weighted_output,
name = "INDProd_disc_numerador"
) |>
# Garante que PPGs sem produção tenham numerador = 0 (boa prática como salvaguarda)
mutate(INDProd_disc_numerador = replace_na(INDProd_disc_numerador, 0)) |>
# Adiciona o total de discentes/egressos para calcular denominador
left_join(students_graduates, by = "Cod PPG") |>
# Calcula denominador ponderado e INDProd final
mutate(
# Denominador: mestres (peso 1) + doutores (peso 2)
INDProd_disc_denominador =
1 * (discente_mestrado_total + egresso_mestrado_total) +
2 * (discente_doutorado_total + egresso_doutorado_total),
A1_A2_count =
1 * (discente_mestrado_estrato_A1_A2 + egresso_mestrado_estrato_A1_A2) +
2 * (discente_doutorado_estrato_A1_A2 + egresso_doutorado_estrato_A1_A2),
A_count =
1 * (discente_mestrado_estrato_A + egresso_mestrado_estrato_A) +
2 * (discente_doutorado_estrato_A + egresso_doutorado_estrato_A),
AB_count =
1 * (discente_mestrado_estrato_AB + egresso_mestrado_estrato_AB) +
2 * (discente_doutorado_estrato_AB + egresso_doutorado_estrato_AB),
A1_A2_prop = if_else(INDProd_disc_denominador == 0, 0,
A1_A2_count * 100 / INDProd_disc_denominador),
A_prop = if_else(INDProd_disc_denominador == 0, 0,
A_count * 100 / INDProd_disc_denominador),
AB_prop = if_else(INDProd_disc_denominador == 0, 0,
AB_count * 100 / INDProd_disc_denominador),
`INDProd disc` = if_else(INDProd_disc_denominador == 0, 0,
INDProd_disc_numerador / INDProd_disc_denominador)
) |>
relocate(INDProd_disc_numerador, .before = INDProd_disc_denominador) |>
select(-matches("count|discente|egresso"))
# For excel users
# Possibilita que o Consultor valide o cálculo na planilha
indprod_disc_check <- students_graduates_output |>
pivot_wider(names_from = Estrato, values_from = n, values_fill = 0, names_sort = T) |>
left_join(students_graduates, by = "Cod PPG") |>
mutate(INDProd_disc_numerador =
(w$a1 * A1) + (w$a2 * A2) + (w$a3 * A3) + (w$a4 * A4) +
(w$b1 * B1) + (w$b2 * B2) + (w$b3 * B3) + (w$b4 * B4) +
(w$l1 * L1) + (w$l2 * L2) + (w$l3 * L3) + (w$l4 * L4) + (w$l5 * L5) +
(w$t1 * T1) + (w$t2 * T2) + (w$t3 * T3) + (w$t4 * T4) + (w$t5 * T5),
INDProd_disc_numerador = replace_na(INDProd_disc_numerador, 0),
INDProd_disc_denominador =
1 * (discente_mestrado_total + egresso_mestrado_total) +
2 * (discente_doutorado_total + egresso_doutorado_total),
`INDProd disc` = INDProd_disc_numerador / INDProd_disc_denominador) |>
arrange(desc(`INDProd disc`))
# CONTAGEM DE DOCENTES PERMANENTES ==========================================
# Número total de Docentes Permanentes por PPG e Ano
dp_count <- dp |>
distinct(`Ano base`, `Cod PPG`, Docente) |>
count(
`Ano base`,
`Cod PPG`,
name = "dp_count"
)
# Número de Docentes Permanentes sêniores por PPG e Ano
# (exclui JPD - Jovens Doutores Permanentes com titulação há 5 anos ou menos)
dp_senior_count <- dp |>
filter(`Ano base` - `Ano Titulação` > 5) |>
distinct(`Ano base`, `Cod PPG`, Docente) |>
count(
`Ano base`,
`Cod PPG`,
name = "dp_senior_count"
)
# Número médio de Docentes Permanentes por PPG no Quadriênio
dp_count_quadri <- dp |>
distinct(`Cod PPG`, `Ano base`, Docente) |>
count(`Cod PPG`, `Ano base`) |>
summarize(
dp_count_quadri = mean(n),
.by = `Cod PPG`
)
contagem <- dp_count |>
left_join(dp_senior_count, by = c("Ano base", "Cod PPG")) |>
left_join(dp_count_quadri, by = c("Cod PPG")) |>
left_join(indprod_disc |>
select(`Cod PPG`, disc_count = INDProd_disc_denominador),
by = "Cod PPG")
# PRODUTIVIDADE DOCENTE ====================================================
# Função para calcular indicadores de produtividade
# Calcula INDProd para docentes permanentes totais e sêniores
calculate_productivity <- function(data, numerator_col, indicator_name) {
data |>
# Adiciona contagem de docentes permanentes por ano e PPG
left_join(dp_count, by = c("Ano base", "Cod PPG")) |>
left_join(dp_senior_count, by = c("Ano base", "Cod PPG")) |>
# Trata valores ausentes e calcula indicadores
mutate(
dp_count = replace_na(dp_count, 0),
dp_senior_count = replace_na(dp_senior_count, 0),
# INDProd = Produção ponderada / Total de docentes permanentes
!!paste0("INDProd ", indicator_name) :=
ifelse(dp_count == 0, 0, !!sym(numerator_col) / dp_count),
# INDProd sênior = Produção ponderada / Docentes sêniores (>5 anos pós-doutorado)
!!paste0("INDProd ", indicator_name, " DP senior") :=
ifelse(dp_senior_count == 0, 0, !!sym(numerator_col) / dp_senior_count)
)
}
# PREPARAÇÃO DOS DADOS DE PRODUÇÃO DOCENTE =================================
# Consolida os DPs por PPG e Ano
producao_docente <- dp |>
select(`Ano base`, `Cod PPG`, Nome = Docente) |>
distinct() |>
# Conecta com produções dos DPs
inner_join(output_autor, by = c("Cod PPG", "Ano base", "Nome")) |>
# Uma produção conta apenas uma vez por PPG e Ano
distinct(`Cod PPG`, `Titulo da Produção`, `Ano base`, Estrato) |>
# Conta produções por PPG, ANO e Estrato
count(`Cod PPG`, `Ano base`, Estrato) |>
# Completa combinações ausentes com zero
complete(`Cod PPG`, `Ano base`, Estrato, fill = list(n = 0)) |>
# Adiciona pesos por estrato e calcula produção ponderada
left_join(weights, by = "Estrato") |>
mutate(weighted_output = n * Weight) |>
# Mantém apenas PPGs e anos presentes nos dados de docentes
semi_join(docente, by = c("Cod PPG", "Ano base"))
# CÁLCULO DOS INDICADORES POR TIPO DE PRODUÇÃO ============================
# INDProd ARTIGOS estratos A (A1-A4)
indprod_article_a_num <- producao_docente |>
filter(str_detect(Estrato, "^[A][1-4]")) |>
count(`Cod PPG`, `Ano base`,
wt = weighted_output, name = "indprod_article_a_num")
# INDProd ARTIGOS estratos B (B1-B4)
indprod_article_b_num <- producao_docente |>
filter(str_detect(Estrato, "^[B][1-4]")) |>
count(`Cod PPG`, `Ano base`,
wt = weighted_output, name = "indprod_article_b_num")
# INDProd ARTIGOS combinado (A + B limitado)
# Regra CAPES: produção B pode contribuir no máximo 25% do indicador final
indprod_artigo <- indprod_article_a_num |>
left_join(indprod_article_b_num, by = c("Cod PPG", "Ano base")) |>
mutate(
indprod_article_a_num = replace_na(indprod_article_a_num, 0),
indprod_article_b_num = replace_na(indprod_article_b_num, 0),
# Limite B: máximo 25% do total => B ≤ A/3 (pois A + B/3 = A × 1.33, B = 25%)
limit_b_25pct_of_final = indprod_article_a_num / 3,
indprod_article_b_num_adj = pmin(indprod_article_b_num, limit_b_25pct_of_final),
# Numerador final: A + B ajustado
indprod_artigo_numerador = indprod_article_a_num + indprod_article_b_num_adj
) |>
# Remove colunas intermediárias
select(-indprod_article_a_num, -indprod_article_b_num,
-indprod_article_b_num_adj, -limit_b_25pct_of_final) |>
# Calcula o indicador final
calculate_productivity("indprod_artigo_numerador", "Artigo")
# INDProd LIVROS (estratos L1-L5)
indprod_livro <- producao_docente |>
filter(str_detect(Estrato, "^[L][1-5]")) |>
count(`Cod PPG`, `Ano base`,
wt = weighted_output, name = "indprod_livro_numerador") |>
calculate_productivity("indprod_livro_numerador", "Livro")
# INDProd PRODUTOS TÉCNICOS E TECNOLÓGICOS - PTT (estratos T1-T5)
indprod_tec <- producao_docente |>
filter(str_detect(Estrato, "^[T][1-5]")) |>
count(`Cod PPG`, `Ano base`,
wt = weighted_output, name = "indprod_tec_numerador") |>
calculate_productivity("indprod_tec_numerador", "PTT")
# INDProd GERAL (todos os estratos qualificados)
indprod_geral <- producao_docente |>
count(`Cod PPG`, `Ano base`,
wt = weighted_output, name = "indprod_geral_numerador") |>
calculate_productivity("indprod_geral_numerador", "Geral")
# TABELA FINAL DE INDICADORES DE PRODUÇÃO ======================================
# Lista com todos os indicadores calculados
indprod_list <- list(
indprod_artigo = indprod_artigo,
indprod_livro = indprod_livro,
indprod_tec = indprod_tec,
indprod_geral = indprod_geral
)
# Combina todos os indicadores em uma única tabela
indprod <- reduce(
indprod_list,
left_join,
by = c("Ano base", "Cod PPG", "dp_count", "dp_senior_count")
) |>
# Remove colunas de numeradores (mantém apenas indicadores finais)
select(-contains("numerador"), -contains("count"))
# Média dos indicadores para o quadriênio
indprod_quadri <- indprod |>
dplyr::group_by(`Cod PPG`) |>
dplyr::summarise(
dplyr::across(dplyr::starts_with("INDProd"),
~ sum(.x, na.rm = TRUE),
.names = "{.col}_sum"),
.groups = "drop"
) |> left_join(dp |>
distinct(`Ano base`, `Cod PPG`) |>
count(`Cod PPG`),
by = "Cod PPG") |>
dplyr::mutate(
dplyr::across(
dplyr::matches("^INDProd.*_sum$"),
~ .x / n,
.names = "{.col}_per_year"
)
) |> select(-ends_with("sum"))
indprod_check <- dp |>
select(`Ano base`, `Cod PPG`, Nome = Docente) |>
distinct() |>
inner_join(output_autor, by = c("Cod PPG", "Ano base", "Nome")) |>
distinct(`Cod PPG`, `Titulo da Produção`, `Ano base`, Estrato) |>
count(`Cod PPG`, `Ano base`, Estrato) |>
pivot_wider(names_from = Estrato, values_from = n,
values_fill = 0, names_sort = T) |>
mutate(INDProd_artigo_numerador_a =
(w$a1 * A1) + (w$a2 * A2) + (w$a3 * A3) + (w$a4 * A4),
INDProd_artigo_numerador_b =
(w$b1 * B1) + (w$b2 * B2) + (w$b3 * B3) + (w$b4 * B4),
limit_b_25pct_of_final = INDProd_artigo_numerador_a / 3,
indprod_article_b_num_adj = pmin(INDProd_artigo_numerador_b, limit_b_25pct_of_final),
INDProd_artigo_numerador = INDProd_artigo_numerador_a + indprod_article_b_num_adj,
INDProd_livro_numerador =
(w$l1 * L1) + (w$l2 * L2) + (w$l3 * L3) + (w$l4 * L4) + (w$l5 * L5),
INDProd_tec_numerador =
(w$t1 * T1) + (w$t2 * T2) + (w$t3 * T3) + (w$t4 * T4) + (w$t5 * T5)
) |>
left_join(dp_count, by = c("Ano base", "Cod PPG")) |>
mutate(
dp_count = replace_na(dp_count, 0),
# Safe division to prevent Inf values
`INDProd Artigo` = ifelse(dp_count > 0, INDProd_artigo_numerador / dp_count, 0),
`INDProd Livro` = ifelse(dp_count > 0, INDProd_livro_numerador / dp_count, 0),
`INDProd PTT` = ifelse(dp_count > 0, INDProd_tec_numerador / dp_count, 0)
) |> right_join(dp |> distinct(`Ano base`, `Cod PPG`),
by = c("Ano base", "Cod PPG")) |>
mutate(across(everything(),
~ replace_na(.x, 0)))
# Resultados convergem?
indprod_disc |>
select(`Cod PPG`, `INDProd disc`) |>
full_join(indprod_disc_check |>
select(`Cod PPG`, `INDProd disc`),
by = "Cod PPG", suffix = c("", "_check")) |>
mutate(check = dplyr::near(`INDProd disc`, `INDProd disc_check`)) |>
summarise(all_methods_converge = all(check, na.rm = TRUE))
## # A tibble: 1 × 1
## all_methods_converge
## <lgl>
## 1 FALSE
indprod |>
select(`Ano base`, `Cod PPG`, `INDProd Artigo`, `INDProd Livro`, `INDProd PTT`) |>
full_join(indprod_check |>
select(`Ano base`, `Cod PPG`, `INDProd Artigo`, `INDProd Livro`, `INDProd PTT`),
by = c("Cod PPG", "Ano base"), suffix = c("", "_check")) |>
mutate(check_artigo = dplyr::near(`INDProd Artigo`, `INDProd Artigo_check`),
check_livro = dplyr::near(`INDProd Livro`, `INDProd Livro_check`),
check_tec = dplyr::near(`INDProd PTT`, `INDProd PTT_check`)) |>
summarise(
all_methods_converge = all(check_artigo, check_livro, check_tec, na.rm = TRUE)
)
## # A tibble: 1 × 1
## all_methods_converge
## <lgl>
## 1 TRUE
# ANÁLISE DOS DESTAQUES =====================================================
# Níveis ordenados de conceitos
conceito_levels <- c("Muito bom", "Bom", "Regular", "Fraco", "Insuficiente", "Não aderente")
# CONTAGEM ABSOLUTA DE DESTAQUES POR CONCEITO =============================
destaques_n <- destaques |>
filter(!is.na(CONCEITO), !is.na(EVENTO), !is.na(`Cod PPG`)) |>
mutate(CONCEITO = factor(CONCEITO, levels = conceito_levels)) |>
count(`Cod PPG`, EVENTO, CONCEITO) |>
complete(`Cod PPG`, EVENTO, CONCEITO, fill = list(n = 0)) |>
arrange(EVENTO, CONCEITO) |>
pivot_wider(
names_from = c(EVENTO, CONCEITO),
names_glue = "{EVENTO}_{CONCEITO}",
values_from = n,
values_fill = 0,
names_sort = FALSE
)
# PROPORÇÃO DE DESTAQUES POR CONCEITO ======================================
destaques_p <- destaques |>
filter(!is.na(CONCEITO), !is.na(EVENTO), !is.na(`Cod PPG`)) |>
mutate(
CONCEITO = factor(CONCEITO, levels = conceito_levels)
) |>
count(`Cod PPG`, EVENTO, CONCEITO) |>
complete(`Cod PPG`, EVENTO, CONCEITO, fill = list(n = 0)) |>
group_by(`Cod PPG`, EVENTO) |>
mutate(
total_n = sum(n),
p = if_else(total_n == 0, 0, n / total_n)
) |>
ungroup() |>
arrange(EVENTO, CONCEITO) |>
select(-n, -total_n) |> # Remove both n and total_n after using them
pivot_wider(
names_from = c(EVENTO, CONCEITO),
names_glue = "{EVENTO}_{CONCEITO}",
values_from = p,
values_fill = 0,
names_sort = FALSE
)
# CONCEITO PREDOMINANTE =====================================
destaques_mark <- destaques |>
filter(!is.na(CONCEITO), !is.na(EVENTO), !is.na(`Cod PPG`)) |>
mutate(
CONCEITO = factor(CONCEITO, levels = conceito_levels)
) |>
count(`Cod PPG`, EVENTO, CONCEITO) |>
complete(`Cod PPG`, EVENTO, CONCEITO, fill = list(n = 0)) |>
group_by(`Cod PPG`, EVENTO) |>
left_join(conceitos, by = "CONCEITO") |>
mutate(Weight = coalesce(Weight, 0)) |>
mutate(
total_n = sum(n),
p = if_else(total_n == 0, 0, n / total_n),
mark = p * Weight
) |>
summarise(nota = sum(mark), .groups = "drop") |>
mutate(conceito = case_when(
nota == 0 ~ "Insuficiente ou não aderente",
nota > 0 & nota < 2.5 ~ "Fraco",
nota >= 2.5 & nota < 5 ~ "Regular",
nota >= 5 & nota < 7.5 ~ "Bom",
nota >= 7.5 ~ "Muito bom"
)) |>
select(-nota) |>
pivot_wider(
names_from = EVENTO,
values_from = conceito,
values_fill = "Insuficiente ou não aderente",
names_sort = FALSE
)
# IMPACTO NA CIÊNCIA =====================================
# Contagem fracionada de publicações -------------------------------------------
# Alternativa* para calcular o indicador de impacto na sociedade (3.1)
# "Cada produto técnico/tecnológico e bibliográfico
# será contabilizado apenas uma vez por PPG."
calculate_fractional_authorship <- function(faculty_data, publication_data,
estrato_filter,
min_publications = 2) {
faculty_list <- faculty_data |>
distinct(`Cod PPG`, Nome = Docente)
authorship_data <- publication_data |>
filter(Estrato == estrato_filter) |>
inner_join(faculty_list, by = c("Cod PPG", "Nome")) |>
select(`Cod PPG`, `Titulo da Produção`, Nome)
fr_counts_publication <- authorship_data |>
count(`Cod PPG`, `Titulo da Produção`) |>
mutate(fr_count = 1 / n)
fr_counts_author <- authorship_data |>
left_join(fr_counts_publication, by = c("Cod PPG", "Titulo da Produção")) |>
count(`Cod PPG`, Nome, wt = fr_count, sort = TRUE, name = "author_output_fr") |>
filter(author_output_fr >= min_publications)
}
docente_output_A1_cont_fr <- calculate_fractional_authorship(
faculty_data = dp,
publication_data = output_autor,
estrato_filter = "A1",
min_publications = 2)
docente_output_A2_cont_fr <- calculate_fractional_authorship(
faculty_data = dp,
publication_data = output_autor,
estrato_filter = "A2",
min_publications = 2)
docente_output_T1_cont_fr <- calculate_fractional_authorship(
faculty_data = dp,
publication_data = output_autor,
estrato_filter = "T1",
min_publications = 2)
docente_output_T2_cont_fr <- calculate_fractional_authorship(
faculty_data = dp,
publication_data = output_autor,
estrato_filter = "T2",
min_publications = 2)
list_of_counts <- list(
A1 = docente_output_A1_cont_fr,
A2 = docente_output_A2_cont_fr,
T1 = docente_output_T1_cont_fr,
T2 = docente_output_T2_cont_fr
)
summaries <- purrr::map(list_of_counts, ~ dplyr::count(.x, `Cod PPG`)) |>
purrr::map2(
names(list_of_counts),
~ dplyr::rename(.x, !!paste0("autores_", .y, "_fr_gte_2") := n)
)
docente_fractional_summary <- purrr::reduce(
.x = summaries,
.f = dplyr::left_join,
by = "Cod PPG",
.init = ppg_key
) |>
right_join(dp_count_quadri, by = "Cod PPG") |>
mutate(
across(
.cols = where(is.numeric) & !any_of("dp_count_quadri"),
.fns = ~ replace_na(.x, 0)
)
) |> mutate(
denom = coalesce(dp_count_quadri, 0),
across(
ends_with("_fr_gte_2"),
~ if_else(denom > 0, .x * 100 / denom, 0),
.names = "{.col}_prop"
)
) |>
select(-denom, -contains("count"))
# --- CONCENTRAÇÃO EDITORIAL E AUTORAL --------------------------------------------
# Índice de Concentração Editorial
# (Número de publicações no periódico mais frequente * 100) / (Total de publicações)
ICE <- output |>
filter(Estrato %in% c("A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4")) |>
distinct(`Cod PPG`, Source, `Titulo da Produção`) |>
count(`Cod PPG`, Source, name = "pub_count") |>
group_by(`Cod PPG`) |>
mutate(
total_pub = sum(pub_count),
ICE = pub_count * 100 / total_pub) |>
slice_max(order_by = pub_count, n = 1, with_ties = TRUE) |>
summarize(
`Periódico mais frequente` = str_c(Source, collapse = " | "),
ICE = first(ICE), # All tied sources have the same ICE value
n_publicacoes_periodico = first(pub_count),
total_publicacoes = first(total_pub)
) |>
select(`Cod PPG`, ICE, `Periódico mais frequente`)
# --- Índice de Concentração Autoral (Alternative Calculation) ---
# Formula: (Número de publicações do autor mais frequente * 100) / (Total de publicações *únicas*)
author_pub_counts <- output_autor |>
filter(Estrato %in% c("A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4")) |>
distinct(`Cod PPG`, Nome, `Titulo da Produção`) |>
count(`Cod PPG`, Nome, name = "pub_count")
total_pub_counts <- output_autor |>
filter(Estrato %in% c("A1", "A2", "A3", "A4", "B1", "B2", "B3", "B4")) |>
distinct(`Cod PPG`, `Titulo da Produção`) |>
count(`Cod PPG`, name = "total_pub_unique")
ICA <- author_pub_counts |>
left_join(total_pub_counts, by = "Cod PPG") |>
group_by(`Cod PPG`) |>
mutate(
ICA = pub_count * 100 / total_pub_unique
) |>
slice_max(order_by = pub_count, n = 1, with_ties = TRUE) |>
summarize(
`Autor mais frequente` = str_c(Nome, collapse = " | "),
ICA = first(ICA), # All tied authors have the same ICA value
n_publicacoes_autor = first(pub_count),
total_publicacoes = first(total_pub_unique) # Using the new total
) |>
select(`Cod PPG`, ICA, `Autor mais frequente`)
# --- ORIENTAÇÕES --------------------------------------------
# Lista de funções para sumarização
summary_funs <- list(
total = ~ sum(.x, na.rm = TRUE),
desvpad = ~ sd(.x, na.rm = TRUE)
)
# Pipeline de transformação de dados
dp_orientacao <- dp |>
# Cria variáveis compostas (ME = peso 1, DO = peso 2)
mutate(
orientacao_andamento = `Orientações em andamento - ME` +
`Orientações em andamento - DO`,
orientacao_concluida =
1 * `Orientações concluídas - ME` +
2 * `Orientações concluídas - DO`
) |>
select(`Ano base`, `Cod PPG`, orientacao_andamento, orientacao_concluida) |>
group_by(`Ano base`, `Cod PPG`) |>
summarise(
across(
.cols = starts_with("orientacao"),
.fns = summary_funs,
.names = "{.fn}_{.col}"
),
.groups = "drop"
) |>
left_join(contagem, by = c("Ano base", "Cod PPG")) |>
mutate(
# Garante que contagens nulas (NA) sejam tratadas como 0
dp_count = replace_na(dp_count, 0),
dp_senior_count = replace_na(dp_senior_count, 0),
# Calcula as médias por tipo de docente
media_orientacao_andamento_dp =
if_else(dp_count == 0, 0, total_orientacao_andamento / dp_count),
media_orientacao_andamento_dp_senior =
if_else(dp_senior_count == 0, 0, total_orientacao_andamento / dp_senior_count),
media_orientacao_concluida_dp =
if_else(dp_count == 0, 0, total_orientacao_concluida / dp_count),
media_orientacao_concluida_dp_senior =
if_else(dp_senior_count == 0, 0, total_orientacao_concluida / dp_senior_count),
# Calcula os Coeficientes de Variação (CV%)
CV_orientacao_andamento =
if_else(media_orientacao_andamento_dp == 0, 0,
desvpad_orientacao_andamento * 100 / media_orientacao_andamento_dp),
CV_orientacao_concluida =
if_else(media_orientacao_concluida_dp == 0, 0,
desvpad_orientacao_concluida * 100 / media_orientacao_concluida_dp)
) |>
select(-starts_with("total"),
-contains("count"))
# --- PUBLICAÇÕES POR ESTRATO -------------------------------
get_estrato_wide <- function(publication_list = output_autor,
affiliation_group = "dp",
count_var = "dp_count") {
publication_list |>
filter(group_key %in% affiliation_group) |>
distinct(`Cod PPG`, `Ano base`, `Titulo da Produção`, Estrato) |>
count(`Ano base`, `Cod PPG`, Estrato) |>
complete(`Cod PPG`, `Ano base`, Estrato, fill = list(n = 0)) |>
right_join(contagem, by = c("Cod PPG", "Ano base")) |>
mutate(norm_value = n / .data[[count_var]]) |>
select(-n, -contains("count")) |>
pivot_wider(names_from = Estrato,
values_from = norm_value, # Or use count_norm if normalized values are desired
values_fill = 0,
names_sort = TRUE)
}
get_estrato_sum <- function(publication_list,
affiliation_group = "dp",
estrato_pattern = "^[AB][1-4]$",
estrato_nome = "AB") {
publication_list|>
filter(group_key %in% affiliation_group) |>
distinct(`Cod PPG`, `Ano base`, `Titulo da Produção`, Estrato) |>
filter(str_detect(Estrato, estrato_pattern)) |>
count(`Ano base`, `Cod PPG`, Estrato) |>
complete(`Cod PPG`, `Ano base`, Estrato, fill = list(n = 0)) |>
right_join(contagem, by = c("Cod PPG", "Ano base")) |>
select(-contains("count")) |>
count(`Cod PPG`, `Ano base`, wt = n, name = estrato_nome) |>
right_join(contagem, by = c("Cod PPG", "Ano base")) |>
mutate(!!sym(estrato_nome) := replace_na(.data[[estrato_nome]], 0)) |>
select(-contains("count"))
}
dp_AB <- get_estrato_sum(publication_list = output_autor,
affiliation_group = "dp",
estrato_pattern = "^[AB][1-4]$",
estrato_nome = "dp_AB")
dp_A <- get_estrato_sum(publication_list = output_autor,
affiliation_group = "dp",
estrato_pattern = "^[A][1-4]$",
estrato_nome = "dp_A")
dp_estrato_sup_prop <- left_join(dp_AB , dp_A, by = c("Ano base", "Cod PPG")) |>
mutate(dp_estrato_sup_prop = ifelse(dp_AB == 0, 0,
dp_A * 100 / dp_AB)) |>
select(-ends_with("_A"), -ends_with("_AB"))
estrato_wide_do <- get_estrato_wide(
publication_list = output_autor,
affiliation_group = "dp",
count_var = "dp_count" # Specify the correct variable
)
estrato_wide_di <- get_estrato_wide(
publication_list = output_autor,
affiliation_group = c("discente_mestrado", "discente_doutorado", "egresso"),
count_var = "disc_count" # Specify the correct variable
)
estrato_wide <- left_join(estrato_wide_do, estrato_wide_di,
by = c("Ano base", "Cod PPG"),
suffix = c("_do", "_di")
)
# --- PROPORÇÕES --------------------------------------------
dp_colab <- docente |>
count(`Ano base`, `Cod PPG`, Categoria) |>
pivot_wider(names_from = Categoria, values_from = n, values_fill = 0) |>
rename(dp_count = PERMANENTE,
colab_count = COLABORADOR) |>
mutate(colab_prop = colab_count * 100 / (dp_count + colab_count),
colab_max_30 = colab_prop >= 30,
colaborador = colab_count
) |>
select(-contains("count"), -contains("VISITANTE"))
dp_estavel_prop <- dp |>
distinct(`Cod PPG`, `Ano base`, Docente) |>
count(`Cod PPG`, Docente) |>
filter(n == 4) |>
count(`Cod PPG`, name = "p_count_quadrienio_estavel") |>
left_join(dp_count_quadri, by = "Cod PPG") |>
mutate(dp_estavel_prop = if_else(coalesce(dp_count_quadri, 0) > 0,
p_count_quadrienio_estavel * 100 / dp_count_quadri, 0)) |>
select(-contains("count"))
dp_carga_horaria_semanal_min_10h <- dp |>
group_by(`Ano base`, `Cod PPG`) |>
summarize(dp_carga_horaria_semanal_min_10h =
any(!is.na(`Carga horária semanal no programa`)) &&
all(`Carga horária semanal no programa` >= 10, na.rm = TRUE))
## `summarise()` has grouped output by 'Ano base'. You can override using the
## `.groups` argument.
dp_min <- contagem |>
mutate(dp_min_12 = dp_count >= 12) |>
select(-contains("count"))
df_prop_data <- tibble::tribble(
~name, ~column,
"dp_exclusivo", "Exclusivo",
"dp_bolsista", "Bolsista CNPq",
"dp_proj_responsavel_discente", "Responsável por Projeto com Participação Discente",
"dp_proj_responsavel_discente_financ", "Responsável com financiamento e participação discente",
"dp_nao_orientou", "Não orientou",
"dp_turma_ministrada", "Turmas ministradas",
"dp_graduacao", "Atividades na Graduação"
)
list_prop_indicators <- pmap(
df_prop_data,
function(name, column, df = dp, df_count = dp_count) {
name_count <- glue("{name}_count")
name_prop <- glue("{name}_prop")
df_count |>
left_join(
df |>
filter(.data[[column]]) |>
count(`Ano base`, `Cod PPG`, name = "x_count"),
by = c("Ano base", "Cod PPG")
) |>
mutate(
x_prop = x_count * 100 / dp_count,
!!name_count := replace_na(x_count, 0),
!!name_prop := replace_na(x_prop, 0)
) |>
select(-x_count, -x_prop)
}
)
prop_indicators <- reduce(list_prop_indicators, left_join,
by = c("Ano base", "Cod PPG")) |>
select(-contains("count"))
prop_summary <- contagem |>
left_join(dp_estavel_prop, by = "Cod PPG") |>
left_join(dp_colab, by = c("Ano base", "Cod PPG")) |>
left_join(dp_carga_horaria_semanal_min_10h, by = c("Ano base", "Cod PPG")) |>
left_join(dp_min, by = c("Ano base", "Cod PPG")) |>
left_join(prop_indicators, by = c("Ano base", "Cod PPG"))
list_ind_por_ano <- list(
prop_summary = prop_summary,
estrato_wide = estrato_wide,
dp_orientacao = dp_orientacao,
dp_estrato_sup_prop = dp_estrato_sup_prop,
indprod = indprod
)
list_ind_por_quadri <-list(
ppg_key = ppg_key,
destaques_mark = destaques_mark,
indprod_disc = indprod_disc,
docente_fractional_summary = docente_fractional_summary,
indprod_quadri = indprod_quadri
)
df_ind_por_ano <- reduce(
list_ind_por_ano,
~ left_join(.x, .y, by = c("Cod PPG", "Ano base"))
)
df_ind_por_quadri <- reduce(
list_ind_por_quadri,
~ left_join(.x, .y, by = c("Cod PPG"))
)
df_ind_ano_quadri <- left_join(df_ind_por_ano, df_ind_por_quadri, by = "Cod PPG")
ppg_year_key <- programa |> distinct(`Ano base`, `Cod PPG`)
final_df <- programa |> left_join(df_ind_ano_quadri,
by = c("Cod PPG", "Ano base")) |>
select(nomes_var$var) |>
arrange(desc(`INDProd Artigo_sum_per_year`), `Cod PPG`,
`Cod PPG`, desc(`Ano base`)) |>
mutate(across(contains("destaque"), ~ case_when(
. == "Muito bom" ~ "MB",
. == "Bom" ~ "B",
. == "Regular" ~ "R",
. == "Fraco" ~ "F",
. == "Insuficiente ou não aderente" ~ "I",
TRUE ~ .
))) |>
mutate(across(where(is.logical), as.numeric))
write_csv(final_df, file = "final_df.csv")