Data Science – Tutorial Extração, Limpeza e Unificação dos Dados Abertos do Prouni com R

Objetivos

  • Entender o que é o Programa Universidade para Todos (Prouni)
  • Saber onde acessar e extrair os dados abertos do Prouni
  • Aprender a realizar manipulação e limpeza de dados
  • Passo a passo para extrair, manipular, limpar e unificar o dataset do Prouni disponibilizado pelo Ministério da Educação (MEC)

O que é o Prouni?

É um programa social criado pelo governo federal, através do Ministério da Educação (MEC). Criado efetivamente em 2004 e já com bolsas disponíveis para o ano seguinte.
O Prouni visa conceder bolsas de estudos complementares (25%), parciais (50%) e integrais (100%) em instituições de ensino superior particulares.

As bolsas complementares (25%) foram uma iniciativa presente em 2008, onde estudantes poderiam solicitar o FIES e complementar 25% do valor com o Prouni.

Existem diversos critérios para que o aluno possa solicitar o Prouni, estes que podem ser verificados diretamente no site oficial do programa.

Dataset (dados) disponíveis do Prouni

Os dados disponíveis do Prouni são os presentes no site de dados abertos do governo federal:

https://dadosabertos.mec.gov.br/prouni

No momento da escrita deste tutorial, somente os dados referentes aos anos de 2005 até 2020 estavam disponíveis.
Para fins de replicabilidade, segue os arquivos que encontramos no site dos dados abertos e o hash. Desta forma, é possível comparar se estamos utilizando versões diferentes do dataset, caso o leitor deste artigo tenha resultados diferentes do esperado.

arquivo	md5	sha1
pda-prouni-2005.csv	8ca2170765eca8944366c3b58c81eeaf	cb579982eba8ce9c303af4db4349c165df4e7284
pda-prouni-2006.csv	e2c7255913e4d06a3f2e3eea7689af6b	b39ae6d21ec796fe3db0f80581e0f77f8f4e0fe8
pda-prouni-2007.csv	8a9e9491228a9c3663d154e975b471df	343d94483bd49fc586506b8a5e4affabe54ebde8
pda-prouni-2008.csv	57d72a8be0fd81a947d73dcdac0c3778	9ef571d484aa6455e1588bbb5643cc964779fa2f
pda-prouni-2009.csv	b48443ae129fb1128f39db925822b02a	70a3dcd403bd1bbb0a52202b23baee7cce169967
pda-prouni-2010.csv	439c1e8437282599878b861b7d11ac43	0380949a5e408ac7e5ba8d073b49cbe9e746df81
pda-prouni-2011.csv	8ecaf8c2a602471122d2d60fb426cfbd	de26faf06149245412e1455c7492e6df7416d238
pda-prouni-2012.csv	093c02c6b44fb4f5d8750e9bccde54ae	cda0697d521777f63bc5d6b5260652609311f571
pda-prouni-2013.csv	2560c46e70ff393123a7bed6ab1a27c8	9b605bbf583f04ffe68fc7fde7e3ed09dc48c301
pda-prouni-2014.csv	bf7faaae1e11b7966dd8d18f5534c199	843bb60219a1b0a60d0e95b24b527d5019009f9f
pda-prouni-2015.csv	8fb5b3ab276c0a0f8533308a839dbb02	002c0bff3c831d29c7ccc69ffe4b65574a546244
pda-prouni-2016.csv	6ba774bb2e703e8417f2a13dfa4ce39d	b40b80e347753c1b649c4feaa5ce27e58adacc7a
pda-prouni-2017.csv	c9a1062ac6b1f6571f4d24750c1a5772	849beb6715a696fb7288b5e13f60d911a81600c7
pda-prouni-2018.csv	c4f385b284056af95f16073cc216d74b	c2d7c795a212142c7648e7781648c23a2f06cc88
pda-prouni-2019.csv	a4bee519238a59fc0eb513016d11ffef	bcefd063f2d76667ebf32986310bfe16b78f7286
pda-prouni-2020.csv	f81f0ec21dcc6d09dd37abdb13732e9a	50f1df4292820e760c1cb17f13211420bcd6b40a

Na lista acima, alteramos o nome dos arquivos para que ficassem no mesmo formato, facilitando a leitura dos arquivos no R. Também tive o cuidado de salvar estes datasets no google drive e disponibilizar para download neste link: Dataset Original dados abertos Prouni anos 2005 até 2020 separados por ano em formato csv

Pré-processamento dos dados

O código completo que vamos utilizar está organizado no fim desta publicação. Mas vamos caminhando e explicando cada etapa. Se só tiver interesse no código pronto, basta ir para o fim do artigo.

Vamos utilizar 2 bibliotecas para leitura e manipulação dos dados:

library(data.table) #para utilizar o fwrite e estrutura data.table
library(cli) #para utilizar hash

Neste passo a passo, vamos levar em conta que já realizou o download dos arquivos do site dos dados abertos. Ao criar um projeto ou script no R, é interessante que defina o seu “working directory” para o projeto, desta forma evita necessidade de referenciar o caminho completo para acessar os dados.

setwd("c:/prouni/")

Vamos criar agora um vetor com todos os anos do Prouni que queremos manipular (isso facilita caso queira acessar só alguns anos):

anos  = c(2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020)

Agora vamos criar uma variável para armazenar o nome dos arquivos que temos disponíveis e verificar o hash MD5 e SHA1:

md5 = sha1 = arquivo = NULL
for (x in anos[1]:anos[length(anos)]) {
  arquivo = append(arquivo, paste("pda-prouni-",x,".csv",sep=""))
  md5     = append(md5,     hash_md5(paste("pda-prouni-",x,".csv",sep="")))
  sha1    = append(sha1,    hash_sha1(paste("pda-prouni-",x,".csv",sep="")))
}
hash = data.frame(arquivo, md5, sha1)

Se digitarmos o nome da variável no console, vamos ter:

               arquivo                              md5                                     sha1
1  pda-prouni-2005.csv 8ca2170765eca8944366c3b58c81eeaf cb579982eba8ce9c303af4db4349c165df4e7284
2  pda-prouni-2006.csv e2c7255913e4d06a3f2e3eea7689af6b b39ae6d21ec796fe3db0f80581e0f77f8f4e0fe8
3  pda-prouni-2007.csv 8a9e9491228a9c3663d154e975b471df 343d94483bd49fc586506b8a5e4affabe54ebde8
4  pda-prouni-2008.csv 57d72a8be0fd81a947d73dcdac0c3778 9ef571d484aa6455e1588bbb5643cc964779fa2f
5  pda-prouni-2009.csv b48443ae129fb1128f39db925822b02a 70a3dcd403bd1bbb0a52202b23baee7cce169967
6  pda-prouni-2010.csv 439c1e8437282599878b861b7d11ac43 0380949a5e408ac7e5ba8d073b49cbe9e746df81
7  pda-prouni-2011.csv 8ecaf8c2a602471122d2d60fb426cfbd de26faf06149245412e1455c7492e6df7416d238
8  pda-prouni-2012.csv 093c02c6b44fb4f5d8750e9bccde54ae cda0697d521777f63bc5d6b5260652609311f571
9  pda-prouni-2013.csv 2560c46e70ff393123a7bed6ab1a27c8 9b605bbf583f04ffe68fc7fde7e3ed09dc48c301
10 pda-prouni-2014.csv bf7faaae1e11b7966dd8d18f5534c199 843bb60219a1b0a60d0e95b24b527d5019009f9f
11 pda-prouni-2015.csv 8fb5b3ab276c0a0f8533308a839dbb02 002c0bff3c831d29c7ccc69ffe4b65574a546244
12 pda-prouni-2016.csv 6ba774bb2e703e8417f2a13dfa4ce39d b40b80e347753c1b649c4feaa5ce27e58adacc7a
13 pda-prouni-2017.csv c9a1062ac6b1f6571f4d24750c1a5772 849beb6715a696fb7288b5e13f60d911a81600c7
14 pda-prouni-2018.csv c4f385b284056af95f16073cc216d74b c2d7c795a212142c7648e7781648c23a2f06cc88
15 pda-prouni-2019.csv a4bee519238a59fc0eb513016d11ffef bcefd063f2d76667ebf32986310bfe16b78f7286
16 pda-prouni-2020.csv f81f0ec21dcc6d09dd37abdb13732e9a 50f1df4292820e760c1cb17f13211420bcd6b40a

Desta forma você poderá confirmar se está utilizando um dataset na mesma versão deste tutorial ou uma versão atualizada pelo governo federal.

Precisamos também definir a normalização dos nomes de cada coluna do Dataset. Já adianto que os anos de 2005 até 2019 possuem 15 variáveis e no ano de 2020 foram adicionadas mais 2.
Vamos primeiramente definir como base os 15 nomes das colunas, criando o seguinte vetor:

nome_colunas = c("ANO_CONCESSAO_BOLSA","CODIGO_EMEC_IES_BOLSA","NOME_IES_BOLSA","TIPO_BOLSA","MODALIDADE_ENSINO_BOLSA","NOME_CURSO_BOLSA","NOME_TURNO_CURSO_BOLSA","CPF_BENEFICIARIO_BOLSA","SEXO_BENEFICIARIO_BOLSA","RACA_BENEFICIARIO_BOLSA","DATA_NASCIMENTO","BENEFICIARIO_DEFICIENTE_FISICO","REGIAO_BENEFICIARIO_BOLSA","SIGLA_UF_BENEFICIARIO_BOLSA","MUNICIPIO_BENEFICIARIO_BOLSA")

Leitura e processamento de arquivos do dataset do Prouni

Para a leitura do dataset, vamos utilizar a função read_delim. Existem diversas outras funções para esta tarefa, a mais rápida testada foi a fread() do pacote data.tables. Porém tive dificuldade para carregar o correto encoding dos arquivos, desta forma tinha problemas com acentuação.

Pelos testes que realizei os datasets do Prouni de 2005-2016 e o 2020 possuem codificação ISO-8859-1. Os datasets de 2017-2019 são UTF-8. A primeira vez que tive contato com estes datasets o ano de 2020 não era compatível com nenhuma codificação que tinha testado. Entrei em contato com o Fala.br e solicitei informação sobre qual codificação utilizar, posteriormente, com o arquivo atualizado, consegui acessar os arquivos com a codificação ISO-8859-1.

Fui informado pelo MEC que os datasets podem ser gerados por equipes distintas, à medida que há mudanças no governo. Isso explicaria a falta de padrão nos arquivos.

Para acessar os arquivos, utilizei então as 2 formas:

#(x < 2017 || x >= 2020)
temp = read_delim(paste("pda-prouni-",x,".csv",sep=""), delim = ";", na = c("", "NA"), escape_double = FALSE, trim_ws = TRUE, col_types = cols(), locale = locale(encoding = "ISO-8859-1"))

#(x > 2017 ||  x < 2020)
temp = read_delim(paste("pda-prouni-",x,".csv",sep=""), delim = ";", na = c("", "NA"), escape_double = FALSE, trim_ws = TRUE, col_types = cols(), locale = locale(encoding = "UTF-8"))

Tendo disponível a data de nascimento do aluno, seria interessante utilizar esse dado para criar posteriormente a faixa-etária dos alunos bolsistas. Pensando nessa possibilidade, já criei uma coluna “ANOS_VIDA”. Porém, tive que ajustar os datasets anteriores a 2017, pois o padrão da data vinha no formato dd-mm-AAAA e o restante do dataset no padrão dd/mm/AAAA.

  if ( x < 2017){
    temp$DATA_NASCIMENTO = as.Date(temp$DATA_NASCIMENTO,"%d-%m-%Y")
    temp$DATA_NASCIMENTO = format(temp$DATA_NASCIMENTO ,"%d/%m/%Y")
  }

Como mencionei o dataset de 2020 veio em outro padrão. Possui 2 colunas a mais “MUNICIPIO” e “CAMPUS”. Como já queria criar uma coluna de ANOS_VIDA, já aproveitei para realizar tudo de uma vez:

  if (x == 2020){
    temp[,"ANOS_VIDA"] = NA #adicionando coluna ANOS_VIDA
    temp = select(temp, 1:3,6:18,4,5) #ordenando colunas
    nome_colunas_2020 = append(nome_colunas, c("ANOS_VIDA","MUNICIPIO","CAMPUS"))
    colnames(temp) = nome_colunas_2020
    #Vamos criar a coluna MUNICIPIO e CAMPUS na variável dados, para poder executar o rbind na mesma proporção de número de colunas
    dados[,"MUNICIPIO"] = NA
    dados[,"CAMPUS"] = NA
  }
  else{
    #Normalizando o nome das colunas dos outros anos
    colnames(temp) = nome_colunas
  }

Com a coluna ANOS_VIDA criada e a variável de nascimento no mesmo padrão, podemos popular a coluna de ANOS_VIDA. Criamos também uma variável data_relativa_idade, pois precisamos calcular a idade do aluno no ano do Prouni. Assim vamos saber a idade do aluno contando com o aniversário que ele fará naquele ano, e não a idade no dia de inscrição do Prouni. Mas caso deseje alterar a data relativa, basta alterar esta variável. Repare que também altero idades inválidas para NA.

data_relativa_idade = as.Date(paste(x,"12","31", sep="/"))
temp$ANOS_VIDA = as.integer(as.numeric(difftime(data_relativa_idade, as.Date(temp$DATA_NASCIMENTO,"%d/%m/%Y"), units = "days"))/365)
temp$ANOS_VIDA[temp$ANOS_VIDA<0] <- NA

Com as mudanças acima, podemos concatenar com uma estrutura de repetição do tipo FOR, todos os datasets de todos os anos em um único data.table (ou data.frame) utilizando o rbind.
Então o código destacado acima ficaria dentro de uma estrutura:

for (x in anos[1]:anos[length(anos)]) {
…

dados = rbind(dados,temp)
}

Limpeza e organização do dataset do Prouni

O dataset não possui muitos dados faltantes, as maiores incoerências encontradas são na data de nascimento dos alunos. Desconfio que talvez na hora que o MEC exportou a data possa ter acontecido algum problema. Ou o aluno tenha inserido sua data de nascimento incorreta, sendo um problema no processo de coleta de dados.

Para eliminar as linhas faltantes, podemos utilizar o comando:

dados = dados[rowSums(is.na(dados)) != ncol(dados), ]

O comando acima só irá remover as linhas em que todos os campos forem ausentes. Verifiquei que algumas linhas em branco foram adicionadas durante o processo de junção dos datasets em um único arquivo. Mas o comando acima corrige este problema.

Outro processo importante é a organização dos dados, a fim de normalizar nomes distintos que correspondem à mesma informação. É interessante que as colunas abaixo sejam definidas com o tipo factor (fator) e níveis definidos:

  • TIPO_BOLSA
  • MODALIDADE_ENSINO_BOLSA
  • NOME_TURNO_CURSO_BOLSA
  • SEXO_BENEFICIARIO_BOLSA
  • BENEFICIARIO_DEFICIENTE_FISICO
  • REGIAO_BENEFICIARIO_BOLSA

Caso não tenha realizado essa mudança no momento que carregou o dataset, não tem problema, vamos realizar o processo abaixo. Repare que também já vamos modificar nomes distintos que definem a mesma informação:

#Normalizar variável TIPO_BOLSA
dados$TIPO_BOLSA = as.factor(dados$TIPO_BOLSA)
levels(dados$TIPO_BOLSA)[levels(dados$TIPO_BOLSA)=="BOLSA INTEGRAL"] <- "INTEGRAL"
levels(dados$TIPO_BOLSA)[levels(dados$TIPO_BOLSA)=="BOLSA PARCIAL 50%"] <- "PARCIAL"
levels(dados$TIPO_BOLSA)[levels(dados$TIPO_BOLSA)=="BOLSA COMPLEMENTAR 25%"] <- "COMPLEMENTAR" #ano de 2008

#Normalizar variável MODALIDADE_ENSINO_BOLSA
dados$MODALIDADE_ENSINO_BOLSA = as.factor(dados$MODALIDADE_ENSINO_BOLSA)
levels(dados$MODALIDADE_ENSINO_BOLSA)[levels(dados$MODALIDADE_ENSINO_BOLSA)=="EDUCAÇÃO A DIST NCIA"] <- "EAD"
levels(dados$MODALIDADE_ENSINO_BOLSA)[levels(dados$MODALIDADE_ENSINO_BOLSA)=="Presencial"] <- "PRESENCIAL"

#Normalizar variável NOME_TURNO_CURSO_BOLSA
dados$NOME_TURNO_CURSO_BOLSA = as.factor(dados$NOME_TURNO_CURSO_BOLSA)
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="CURSO A DIST NCIA"] <- "EAD"
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="Curso a distância"] <- "EAD"
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="Integral"] <- "INTEGRAL"
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="Matutino"] <- "MATUTINO"
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="Noturno"] <- "NOTURNO"
levels(dados$NOME_TURNO_CURSO_BOLSA)[levels(dados$NOME_TURNO_CURSO_BOLSA)=="Vespertino"] <- "VESPERTINO"

#Normalizar variável SEXO_BENEFICIARIO_BOLSA
dados$SEXO_BENEFICIARIO_BOLSA = as.factor(dados$SEXO_BENEFICIARIO_BOLSA)
levels(dados$SEXO_BENEFICIARIO_BOLSA)[levels(dados$SEXO_BENEFICIARIO_BOLSA)=="Feminino"] <- "F"
levels(dados$SEXO_BENEFICIARIO_BOLSA)[levels(dados$SEXO_BENEFICIARIO_BOLSA)=="Masculino"] <- "M"

#Normalizar variável BENEFICIARIO_DEFICIENTE_FISICO
dados$BENEFICIARIO_DEFICIENTE_FISICO = as.factor(dados$BENEFICIARIO_DEFICIENTE_FISICO)
levels(dados$BENEFICIARIO_DEFICIENTE_FISICO)[levels(dados$BENEFICIARIO_DEFICIENTE_FISICO)=="SIM"] <- "S"
levels(dados$BENEFICIARIO_DEFICIENTE_FISICO)[levels(dados$BENEFICIARIO_DEFICIENTE_FISICO)=="NÃO"] <- "N"

#Normalizar variável REGIAO_BENEFICIARIO_BOLSA
dados$REGIAO_BENEFICIARIO_BOLSA = as.factor(dados$REGIAO_BENEFICIARIO_BOLSA)
levels(dados$REGIAO_BENEFICIARIO_BOLSA)[levels(dados$REGIAO_BENEFICIARIO_BOLSA)=="Centro-Oeste"] <- "CENTRO-OESTE"
levels(dados$REGIAO_BENEFICIARIO_BOLSA)[levels(dados$REGIAO_BENEFICIARIO_BOLSA)=="Nordeste"] <- "NORDESTE"
levels(dados$REGIAO_BENEFICIARIO_BOLSA)[levels(dados$REGIAO_BENEFICIARIO_BOLSA)=="Norte"] <- "NORTE"
levels(dados$REGIAO_BENEFICIARIO_BOLSA)[levels(dados$REGIAO_BENEFICIARIO_BOLSA)=="Sudeste"] <- "SUDESTE"
levels(dados$REGIAO_BENEFICIARIO_BOLSA)[levels(dados$REGIAO_BENEFICIARIO_BOLSA)=="Sul"] <- "SUL"

Com os comandos acima a base de dados já estará unificada e organizada. É interessante então gerar um novo arquivo unificado, vamos chamar de pda-prouni-2005-2020.csv. Vamos criar um hash deste novo arquivo e juntar com o hash dos arquivos de dataset de origem e também salvar em disco com o nome hash-datasets.txt. Este passo é importante para fins de reprodutibilidade posteriormente.

#Salvar o arquivo gerado em disco
dataset_saida = "pda-prouni-2005-2020.csv"
fwrite(dados, dataset_saida)

#Criar o hash para o arquivo de dataset unificado que acabamos de criar
hash = rbind(hash, data.frame(arquivo=dataset_saida, md5=hash_md5(dataset_saida), sha1=hash_sha1(dataset_saida)))
fwrite(hash, "hash-datasets.txt", sep = " \t ")

Com o passo acima temos uma base uniforme do Prouni referente aos anos de 2005-2020, facilitando o processo de análise e ciência de dados. O código também está disponível abaixo, de forma organizada:

Ao executar o código acima, gerei um dataset unificado. Deixo ele disponível para download neste link: Dataset completo Prouni 2005 até 2020 – Portal dados Abertos

Gostou do conteúdo? Tem alguma sugestão para melhorar o código acima? Quer mais funcionalidades presentes? Deixa sua mensagem aí nos comentários, que farei o possível para responder!