Analista de Dados Cientista de Dados
Construção de um Data Warehouse utilizando a linguagem Python aliada ao SQLite para para os Micrododados do ENADE dos anos de 2017, 2018 e 2019 disponibilizados pelo Governo, seguida de uma análise de dados e um modelo de predição.
O escopo do projeto é dividido em três partes. Primeiramento, é construído um Data Warehouse seguindo uma modelagem dimensional estrela com os microdados do ENADE do anos de 2017, 2018 e 2019 disponibilizados no site do INEP. A partir de consultas ao Data Warehouse elaborado, é então realizada uma Análise Exploratória para por fim construir um modelo de aprendizagem de máquina com a finalidade de predizer o desempenho de um aluno com base em informações preenchidas nas provas como dados da instituição, características e perfil socioeconômico do aluno. As bases de dados importadas possuem 169 variáveis, mas no presente projeto algumas foram descartadas. Todo o trabalho está disponível em um repositório do Github [1].
O ENADE, sigla para Exame Nacional de Desempenho de Estudantes, é uma exame anual que tem como objetivo avaliar o conhecimento obtidos em relação aos conteúdos previstos na grade curricular do respectivo curso de graduação dos estudantes acadêmicos que estão prestes a se formar. Dessa forma, todo ano, alunos concluintes do ensino superior são submetidos a uma prova de conhecimento geral e específico composta por questões objetivas e discursivas. Além das questões para avaliar o conhecimento do estudante, as provas também apresentam questionários para obter informações socionômicas e experiências acadêmicas do estudante, além de seu preparo para a prova, percepção sobre a mesma e avaliação da Instituição. Todas essas informações obtidas em cada ano são disponibilizadas pelo INEP como microdadados.
Para o desenvolvimento deste trabalho foram utilizados os microdados do Enade disponibilizados pelo site do INEP [2]. A pesquisa se baseou em dados de todos os estudantes que realizaram o exame no ano de 2017, 2018 e 2019. Dentre os dados disponíveis estão:
Informações do Curso, da Instituição de Ensino Superior e da sua localização
Informações Sociais do Estudante como gênero e idade
Avaliação - Formação Geral e Componente Específico
Nota Geral e todas as notas que a compoem
Presença do Aluno no Enade e nas seções das provas
Gabarito das questões objetivas e as respostas marcadas pelo aluno
Questionário do Estudante, com questões socioeconômicas e questões sobre sua vida acadêmica
Totalizando 182 atributos na base de 2017 e 169 em cada umas das outras bases. Essa diferença se dá por varáveis que estão presentes apenas na base de 2017 referentes à questões específicas do curso de licenciatura. Dessa forma, como esses atributos são específicos para um grupo de cursos e não estão presentes em todas as bases, dificultando assim uma integração para uma análise exploratória, foram descartados neste trabalho.
As informações são disponibilizadas no formato TXT acompanhadas de um dicionário de variáveis no formato XLS que apresenta uma aba com a descrição do que significa cada atributo e seus possíveis valores e outra aba com atributos identificadores de cada código de cidade disponibilizados pelo IBGE, já que os microdados aprensentam apenas esses códigos na identifição do local do curso.
Além dos dados descritos acima, foram também utilizados nesse trabalho as bases também fornecidas pelo INEP que apresentam o Conceito ENADE de cada ano e podem ser encontradas na página do INEP [3]. Essas bases foram utilizadas com a finalidade de obter atributos referentes à alguns códigos que aparecem no microdados do ENADE como nome da instituição.
Para realizar extração de todas os dados listados anteriormente de forma automatizada, utilizou-se o script “00_Download_Dados” desenvolvido em um notebook jupyter com linguagem python que ao ser executado, realiza o donwload dos microdados do enade e dos dados do Conceito enade e os salva em uma pasta denominada de “Dados” no mesmo diretório em que se encontra o script. As funções do script podem ser observadas abaixo
# Python versão 3.8.8
# Windows 10
# biblioteca para realizar requisição
import requests # versão 2.25.1
# biblioteca para interação com o sistema
import os
# import shutil
diretorio_atual = os.path.dirname(os.path.realpath('__file__')) + "\\"
diretorio_dados = diretorio_atual + "Dados\\"
#Função para realizar o download de um arquivo através de uma url e salva-lo no diretório dado
def download_arquivo(url, path_arquivo, nome_arquivo):
# Cria a o pasta se não existe ainda no diretório ainda
if not os.path.exists(path_arquivo):
os.makedirs(path_arquivo)
mensagem_download = "Realizando Download do Arquivo '{}'...".format(nome_arquivo)
mensagem_sucesso = 'Arquivo {} salvo com sucesso.'.format(nome_arquivo).ljust(len(mensagem_download))
print(mensagem_download, end="\r", flush=True)
requisicao_arq = requests.get(url, path_arquivo + nome_arquivo)
url_content = requisicao_arq.content
csv = open(path_arquivo + nome_arquivo, 'wb')
csv.write(url_content)
csv.close()
print(mensagem_sucesso, end="\n")
# Funcao para baixar os microdados do ENADE dos anos 2017, 2018 e 2019
def download_microdados_enade(download_novamente = False):
# Links para download dos microdados
url_enade_2019 = "https://download.inep.gov.br/microdados/Enade_Microdados/microdados_enade_2019.zip"
url_enade_2018 = "https://download.inep.gov.br/microdados/Enade_Microdados/microdados_enade_2018.zip"
url_enade_2017 = "https://download.inep.gov.br/microdados/Enade_Microdados/microdados_Enade_2017_portal_2018.10.09.zip"
urls = [url_enade_2017, url_enade_2018, url_enade_2019]
pasta_microdados = diretorio_dados + "Microdados_ENADE\\"
for url in urls:
print("\n", end = "\r")
nome_arquivo = url.split("/")[-1]
nome_arquivo = "_".join(nome_arquivo.split("_")[:3]).replace(".zip", "").lower() + ".zip"
existe_arquivo = os.path.isfile(pasta_microdados + nome_arquivo)
if not download_novamente:
if (existe_arquivo):
print("Arquivo '{}' já se encontra no diretório.".format(nome_arquivo), end="\n")
print("Caso deseje baixar novamente, descomente a célula abaixo".format(nome_arquivo), end="\n")
print("-" * 90)
continue
download_arquivo(url, pasta_microdados, nome_arquivo)
download_microdados_enade(download_novamente = True)
# Funcao para baixar os dados do conceito ENADE dos anos 2017, 2018 e 2019
def download_conceito_enade(download_novamente = False):
# Links para download dos microdados
url_conceito_2019 = "https://download.inep.gov.br/educacao_superior/indicadores/resultados/2019/Conceito_Enade_2019.xlsx"
url_conceito_2018 = "https://download.inep.gov.br/educacao_superior/indicadores/legislacao/2019/resultados_conceito_enade_2018.xlsx"
url_conceito_2017 = "https://download.inep.gov.br/educacao_superior/indicadores/legislacao/2018/resultados_conceito_enade_2017.xlsx"
urls = [url_conceito_2017, url_conceito_2018, url_conceito_2019]
pasta_microdados = diretorio_dados + "Conceito_ENADE\\"
for url in urls:
print("\n", end = "\r")
nome_arquivo = url.split("/")[-1]
nome_arquivo = nome_arquivo.replace("resultados_","").lower()
existe_arquivo = os.path.isfile(pasta_microdados + nome_arquivo)
if not download_novamente:
if (existe_arquivo):
print("Arquivo '{}' já se encontra no diretório.".format(nome_arquivo), end="\n")
print("Caso deseje baixar novamente, descomente a célula abaixo".format(nome_arquivo), end="\n")
print("-" * 90)
continue
download_arquivo(url, pasta_microdados, nome_arquivo)
download_conceito_enade(download_novamente = True)
No presente trabalho foi utilizada a modelagem Estrela (Star Schema) caracterizada por poucas tabelas e relacionamentos, onde todas as tabelas de Dimensão se relacionam direta e unicamente com a tabela Fato, sendo assim um modelo simples e eficiente.
Para construção do modelo, o dataset passou foi avaliado e passou por tratamento de dados. O dataset apresenta algumas linhas que não apresentam notas das provas, escolhidas para serem fatos da modelagem e target do modelo, assim foi decidido pela remoção desses casos. Também foi optado pela remoção de nulos da coluna “QI_01” já que foi oberservado que essas amostras também apresentavam valores nulos em quase todas as outras colunas pertencetes ao questionário. Uma outra remoçào foi a de amostras com idades duvidosas como 4 e 11 anos, assim foi criado um filtro para só incluir linhas que apresentam idade maior ou igual à 16. Assim, após todas as remões feitas, o dataset final ficou com 1.291.772 linhas.
Outro tratamento feito foi a substituição de valores pelos seus significados apresentados no dicionário de dados nas colunas. Algumas colunas possuiam valores diferentes em cada ano que possuiam o mesmo significado, nesses casos, foram obtidas informaçòes de todos os dicionários para que todos os valores fossem substuídos, ocasionando numa mesma substituição para valores diferentes.
Todas essas manipulações podem ser observadas no script python “01_Criação_Banco_de_Dados.ipynb” na sessão onde as tabelas de dimensão e fato são construídas.
# Python versão 3.8.8
# Windows 10
# biblioteca para realizar requisição
import requests # versão 2.25.1
# biblioteca para interação com o sistema
import os
import shutil
# biblioeca para manipulação de dados
import pandas as pd # versão 1.3.2
from pandas.api.types import is_integer_dtype, is_object_dtype, is_float_dtype
import numpy as np
import unidecode
from zipfile import ZipFile
import warnings
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')
from colorama import Fore, Style # versão 0.4.4
import sqlite3
# Endereço do diretório onde se encontra o script python
diretorio_atual = os.path.dirname(os.path.realpath('__file__')) + "\\"
# Endereço do diretório onde se encontram os dados
diretorio_dados = diretorio_atual + "Dados\\"
# Nome do Banco de Dados que será criado
nome_bd = "Enade_DW.sqlite"
df_2017_importado = pd.DataFrame()
df_2018_importado = pd.DataFrame()
df_2019_importado = pd.DataFrame()
df_cod_cidades_importado = pd.DataFrame()
df_dicionario_importado = pd.DataFrame()
df_con_2017_importado = pd.DataFrame()
df_con_2018_importado = pd.DataFrame()
df_con_2019_importado = pd.DataFrame()
# Função para ler os microdados dos anos 2017, 2018 e 2019 do ENADE baixados pelo script 00
def leitura_microdados():
global df_2017_importado, df_2018_importado, df_2019_importado, df_enade_2017, df_enade_2018, df_enade_2019
diretorio_enade = diretorio_dados + "Microdados_ENADE\\"
if not len(df_2017_importado):
print("Carregando Microdados do ano 2017...", end="\r", flush=True)
zip_ano = ZipFile(diretorio_enade + "microdados_enade_2017.zip")
arquivo = "3.DADOS/MICRODADOS_ENADE_2017.txt"
df_2017_importado = pd.read_csv(zip_ano.open(arquivo), sep=';', low_memory=False)
df_enade_2017 = df_2017_importado.copy()
print(f'Microdados do ano 2017 importados com sucesso para a variável {Fore.GREEN}df_enade_2017{Style.RESET_ALL}', end="\n\n")
if not len(df_2018_importado):
print("Carregando Microdados do ano 2018...", end="\r", flush=True)
zip_ano = ZipFile(diretorio_enade + "microdados_enade_2018.zip")
arquivo = "2018/3.DADOS/microdados_enade_2018.txt"
df_2018_importado = pd.read_csv(zip_ano.open(arquivo), sep=';', low_memory=False)
df_enade_2018 = df_2018_importado.copy()
print(f'Microdados do ano 2018 importados com sucesso para a variável {Fore.GREEN}df_enade_2018.{Style.RESET_ALL}', end="\n\n")
if not len(df_2019_importado):
print("Carregando Microdados do ano 2019...", end="\r", flush=True)
zip_ano = ZipFile(diretorio_enade + "microdados_enade_2019.zip")
arquivo = "3.DADOS/microdados_enade_2019.txt"
df_2019_importado = pd.read_csv(zip_ano.open(arquivo), sep=';', low_memory=False)
df_enade_2019 = df_2019_importado.copy()
print(f'Microdados do ano 2019 importados com sucesso para a variável {Fore.GREEN}df_enade_2019.{Style.RESET_ALL}', end="\n\n")
leitura_microdados()
# Função para ler o dicionário com códigos das cidades do IBGE que se encontra no dicionário dos Microdados
# do ENADE baixados pelo script 00
def leitura_cod_cidades():
global df_cod_cidades_importado, df_cod_cidades
diretorio_enade = diretorio_dados + "Microdados_ENADE\\"
if not len(df_cod_cidades_importado):
zip_ano = ZipFile(diretorio_enade + "microdados_enade_2019.zip")
arquivo = "1.LEIA-ME/Dicionário de variáveis dos Microdados do Enade 2019.xlsx"
# print("Carregando Microdados do ano {}...".format(ano), end="\r", flush=True)
df_cod_cidades_importado = pd.read_excel(zip_ano.open(arquivo), sheet_name='MUNICÍPIOS',
skiprows = 3, header = 0, usecols = "B:D")
df_cod_cidades = df_cod_cidades_importado.copy()
print(f'Dados dos Códigos das Cidades importados com sucesso para a variável {Fore.GREEN}df_cod_cidades.{Style.RESET_ALL}', end="\n\n")
leitura_cod_cidades()
def leitura_conceito_ENADE():
global df_con_2017_importado, df_con_2018_importado, df_con_2019_importado, df_con_2017, df_con_2018, df_con_2019
diretorio_conceito = diretorio_dados + "Conceito_ENADE\\"
anos_enade = ["2017","2018","2019"]
for ano in anos_enade:
if not len(globals()[f'df_con_{ano}_importado']):
globals()[f'df_con_{ano}_importado'] = pd.read_excel(diretorio_conceito + f'conceito_enade_{ano}.xlsx')
globals()[f'df_con_{ano}'] = globals()[f'df_con_{ano}_importado'].copy()
print(f'Conceito do ENADE do ano {ano} importado com sucesso para a variável {Fore.GREEN}df_con_{ano}{Style.RESET_ALL}',
end="\n\n")
leitura_conceito_ENADE()
def leitura_dicionarios():
global df_dicionario_importado, df_dicionario
diretorio_enade = diretorio_dados + "Microdados_ENADE\\"
if not len(df_dicionario_importado):
zip_ano = ZipFile(diretorio_enade + "microdados_enade_2017.zip")
arquivo = "1.LEIA-ME/Dicionário de variáveis dos Microdados do Enade_Ediç╞o 2017.xlsx"
df_dicionario_importado = pd.read_excel(zip_ano.open(arquivo), sheet_name='DICIONÁRIO', skiprows = 1,
header = 0, usecols = "B:F")
df_dicionario_importado = df_dicionario_importado.dropna(axis = 0).reset_index(drop = True)
df_dicionario = df_dicionario_importado.copy()
print(f'Dicionário dos Microdados importados com sucesso para a variável {Fore.GREEN}df_dicionario.{Style.RESET_ALL}', end="\n\n")
leitura_dicionarios()
colunas_so_2017 = list(set(df_enade_2017.columns) - set(df_enade_2018.columns))
df_enade_2017 = df_enade_2017.drop(columns = colunas_so_2017)
df_enade_17_18_19 = pd.concat([df_enade_2017, df_enade_2018, df_enade_2019]).reset_index(drop = True)
df_enade_17_18_19.shape
df_con_17_18_19 = pd.concat([df_con_2017, df_con_2018, df_con_2019]).reset_index(drop = True)
# df_enade_17_18_19.sample(4)
df_enade_17_18_19 = df_enade_17_18_19.replace(' ', np.nan)
# Como a Nota é um fato, foram elinadas as amostras que não apresentam nota
df_enade_17_18_19 = df_enade_17_18_19[df_enade_17_18_19["NT_GER"].notna()].reset_index(drop = True)
df_enade_17_18_19.shape
turno_maisf_ies = df_enade_17_18_19.groupby(['CO_IES'])["CO_TURNO_GRADUACAO"].agg(pd.Series.mode).to_frame()
dicionario_turno_ies = dict(zip(turno_maisf_ies.index, turno_maisf_ies['CO_TURNO_GRADUACAO']))
index_nan = df_enade_17_18_19[df_enade_17_18_19["CO_TURNO_GRADUACAO"].isna()].index.to_list()
for index in index_nan:
cod_ies = df_enade_17_18_19.CO_IES[index].copy()
try:
df_enade_17_18_19.CO_TURNO_GRADUACAO[index] = dicionario_turno_ies[cod_ies].copy()
except:
pass
df_enade_17_18_19.CO_TURNO_GRADUACAO.value_counts(dropna = False)
# As colunas abaixo são colunas presentes nas dimensões que apresentam nulos, como o número é baixo comparado ao
# tamanho total da base de dados, foi optado a remoção de nulos
df_enade_17_18_19 = df_enade_17_18_19[df_enade_17_18_19.CO_TURNO_GRADUACAO.notna()].reset_index(drop = True) # 292 nulos
df_enade_17_18_19 = df_enade_17_18_19.dropna(subset=["QE_I01"]).reset_index(drop = True) # 10231 nulos
df_enade_17_18_19.shape
#Há casos de 1 amostra com estudante com idade igual 4, 3 igual a 11 e 1 igual 12
df_enade_17_18_19 = df_enade_17_18_19[df_enade_17_18_19["NU_IDADE"] > 12]
df_enade_17_18_19 = df_enade_17_18_19.rename(columns = {"NU_ANO": "ID_TEMPO"})
O modelo elaborado neste trabalho foi desenvolvido com o intuito de ser centrado nas notas das provas, objetivando fornecer dados para análise de fatores que influenciam no desempenho de cada aluno que presta a avaliação. Dessa forma, o modelo apresenta como fato a prova que possui como métrica a nota final e as notas de formação geral e componente específico que a compoem, além de 11 tabelas de dimensão. A modelagem pode ser observada no diagrama abaixo que foi elaborado com a ferramenta Visual Paradigm:
Figura 1: Modelagem dimensional Estrela Microdados ENADE [4]
Para selecionar as variáveis que compõem as tabelas, primeiro foram descartadas aquelas que não estavam presentes em todas as bases, sendo assim romovidas 13 variáveis presentes apenas nos microdados do ano de
ID_ALUNO_ECONOMICO | Numérico | Chave Primária |
---|---|---|
PESSOAS_MORAM_JUNTO | Categórico | Quantidade de pessoas que moram junto com o estudante. Adaptação da coluna QE_I07 onde os códigos foram substituídos pelos significados presente no dicionário. |
RENDA_FAMILIAR | Categórico | Categoria de renda familiar do estudante. Adaptação da coluna QE_I08 onde os códigos foram substituídos pelos significados presente no dicionário. |
HORAS_TRABALHO | Categórico | Tempo que estudante trabalha em média por semana. Adaptação da coluna QE_I10 onde os códigos foram substituídos pelos significados presente no dicionário. |
AUXILIO_RECEBIDO | Categórico | Indicação se o estudante recebe auxílio. Adaptação da coluna QE_I12 onde os códigos foram substituídos pelos significados presente no dicionário. |
ENTROU_POR_COTA | Categórico | Indicação se o estudante entrou por cota. Adaptação da coluna QE_I15 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_TEMPO | Numérico | Chave Primária |
---|---|---|
ANO | Numérico | Ano da prova. A coluna foi renomeada, o nome original é NU_ANO. |
ID_IES_ANO | Numérico | Chave Primária |
---|---|---|
NOME_IES | Categórico | Nome da Instituição de Ensino Superior. Coluna foi construída com os dados presentes na base Conceito Enade. |
CATEGORIA_IES | Categórico | Categoria Asministrativa da Instituição de Ensino Superior. Adaptação da coluna CO_CATEGAD onde os códigos foram substituídos pelos significados presente no dicionário. |
ORGANIZACAO_IES | Categórico | Organização Acadêmica da Instituição de Ensino Superior. Adaptação da coluna CO_ORGACAD onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_ALUNO_ENSINO_MEDIO | Numérico | Chave Primária |
---|---|---|
TIPO_ESCOLA_EM | Categórico | Tipo de escola em que o estudante cursou o ensino médio. Adaptação da coluna QE_I17 onde os códigos foram substituídos pelos significados presente no dicionário. |
MODALIDADE_EM | Categórico | Modalidade do Ensino Médio cursado pelo aluno. Adaptação da coluna QE_I18 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_FORMACAO_FAMILIA | Numérico | Chave Primária |
---|---|---|
ESCOLARIZACAO_PAI | Categórico | Escolarização do pai do estudante. Adaptação da coluna QE_I04 onde os códigos foram substituídos pelos significados presente no dicionário. |
ESCOLARIZACAO_MAE | Categórico | Escolarização do mãe do estudante. Adaptação da coluna QE_I05 onde os códigos foram substituídos pelos significados presente no dicionário. |
FAMILIAR_GRADUADO | Categórico | Existência de algum familiar graduado. Adaptação da coluna QE_I21 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_CURSO | Numérico | Chave Primária |
---|---|---|
MODALIDADE_CURSO | Categórico | Modalidade de ensino do curso. Adaptação da coluna CO_MODALIDADE onde os códigos foram substituídos pelos significados presente no dicionário. |
GRUPO_CURSO | Categórico | Área de Enquadramento do curso. Adaptação da coluna CO_GRUPO onde os códigos foram substituídos pelos significados presente no dicionário. |
CO_MUNIC_CURSO | Numérico | Chave Primária |
---|---|---|
NOME_MUNICIPIO | Categórico | Município da Instituição. Construida a partir da aba “MUNICÍPIOS” presente na planilha do Dicionário. |
UF | Categórico | UF referente ao Estado da Instituição. Construida a partir da aba “MUNICÍPIOS” presente na planilha do Dicionário. |
REGIAO_CURSO | Categórico | Região da Instituição. Adaptação da coluna CO_UF_CURSO onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_PERCEPCAO_PROVA | Numérico | Chave Primária |
---|---|---|
GRAU_DIFICULDADE_FG | Categórico | Indicação do estudante sobre o dificuldade que apresentou na seção de formação geral. Adaptação da coluna CO_RS_I1 onde os códigos foram substituídos pelos significados presente no dicionário. |
GRAU_DIFICULDADE_CE | Categórico | Indicação do estudante sobre o dificuldade que apresentou na seção de componente específico. Adaptação da coluna CO_RS_I2 onde os códigos foram substituídos pelos significados presente no dicionário. |
PERC_EST_CONTEUDO | Categórico | Percepção do estudante sobre o estudo do conteúdo cobrado. Adaptação da coluna CO_RS_I8 onde os códigos foram substituídos pelos significados presente no dicionário. |
TEMPO_GASTO_PROVA | Categórico | Estimativa de tempo que o aluno levou para concluir a prova. Adaptação da coluna CO_RS_I9 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_PRESENCA | Numérico | Chave Primária |
---|---|---|
TP_PR_OB_FG | Booleano | Indicação de presença do estudante na parte objetiva da formação geral. Os valores da coluna foram alterados, onde as códigos que representavam algum tipo de participação no dicionário foram substituídos por 1 e todo o respot por 0. |
TP_PR_DI_FG | Booleano | Indicação de presença do estudante na parte discursiva da formação geral. Os valores da coluna foram alterados, onde as códigos que representavam algum tipo de participação no dicionário foram substituídos por 1 e todo o respot por 0. |
TP_PR_OB_CE | Booleano | Indicação de presença do estudante na parte objetiva do componente específico. Os valores da coluna foram alterados, onde as códigos que representavam algum tipo de participação no dicionário foram substituídos por 1 e todo o respot por 0. |
TP_PR_DI_FG | Booleano | Indicação de presença do estudante na parte discursiva do componente específico. Os valores da coluna foram alterados, onde as códigos que representavam algum tipo de participação no dicionário foram substituídos por 1 e todo o resto por 0. |
ID_OPORTUNIDADES | Numérico | Chave Primária |
---|---|---|
ATIVIDADES_CURRICURALES_EXTERIOR | Categórico | Experiência em atividades extracurriculares no exterior. Adaptação da coluna QE_I14 onde os códigos foram substituídos pelos significados presente no dicionário. |
IDIOMA_ESTRANGEIRO | Categórico | Experiência em curso de idimoa estrangeiro na Instituição. Adaptação da coluna QE_I24 onde os códigos foram substituídos pelos significados presente no dicionário. |
EXTENSAO_UNIVERSITARIA | Categórico | Oportunidades para participação em atividades de extensão na Universidade. Adaptação da coluna QE_I43 onde os códigos foram substituídos pelos significados presente no dicionário. |
ATIVIDADES_INVESTIGACAO_ACADEMICA | Categórico | Oportunidades para participação em projetos como IC na Instituição. Adaptação da coluna QE_I44 onde os códigos foram substituídos pelos significados presente no dicionário. |
INTERCAMBIO_ESTAGIO_PAIS | Categórico | Oportunidades para intercambio e/ou estágio no país. Adaptação da coluna QE_I52 onde os códigos foram substituídos pelos significados presente no dicionário. |
INTERCAMBIO_ESTAGIO_FORA_DO_PAIS | Categórico | Oportunidades para intercambio e/ou estágio fora do país Adaptação da coluna QE_I53 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_ALUNO_INFO | Numérico | Chave Primária |
---|---|---|
NU_IDADE | Numérico | Idade do estudante. |
TP_SEXO | Categórico | Gênero do estudante. |
CO_TURNO_GRADUACAO | Numérico | Turno da graduação do estudante. |
ESTADO_CIVIL | Categórico | Estado civil do estudante. Adaptação da coluna QE_I01 onde os códigos foram substituídos pelos significados presente no dicionário. |
RAÇA | Categórico | Raça autodeclarada do estudante. Adaptação da coluna QE_I02 onde os códigos foram substituídos pelos significados presente no dicionário. |
NACIONALIDADE | Categórico | Nacionalidade do estudante. Adaptação da coluna QE_I03 onde os códigos foram substituídos pelos significados presente no dicionário. |
ID_PROVA | Numérico | Chave Primária |
---|---|---|
ID_ALUNO_ECONOMICO | Numérico | Chave Estrangeira |
ID_CURSO | Numérico | Chave Estrangeira |
ID_ALUNO_ENSINO_MEDIO | Numérico | Chave Estrangeira |
ID_FORMACAO_FAMILIA | Numérico | Chave Estrangeira |
ID_IES_ANO | Numérico | Chave Estrangeira |
ID_ALUNO_INFO | Numérico | Chave Estrangeira |
ID_OPORTUNIDADES | Numérico | Chave Estrangeira |
ID_PERCEPCAO_PROVA | Numérico | Chave Estrangeira |
ID_PRESENCA | Numérico | Chave Estrangeira |
CO_MUNIC_CURSO | Numérico | Chave Estrangeira |
ID_TEMPO | Numérico | Chave Estrangeira |
ID_ALUNO_INFO | Numérico | Chave Estrangeira |
NT_ GER | Numérico | Nota geral da prova. |
NT_ CE | Numérico | Nota do componente específico da prova. |
NT_ FG | Numérico | Nota da formação geral da prova. |
Para criação do banco de dados relacional deste trabalho foi escolhido a utilização do sistema de gerenciamento sqlite por possuir uma gerenciamento mais simples através do python. Para alimentar o banco de dados com as tabelas criadas pela modelagem dimensional, foi utlizado o script “01_Criação_Banco_de_Dados.ipynb” em python que utiliza a biblioteca “sqlite3” para realizar a comunicação com o banco. Para isso, o script primeiro verifica se há o banco de dados “Enade_DW.sqlite” em seu diretório, se não , o cria. Em seguida, realiza todas as manipulações no dataset para criação das tabelas.
Com a conexão ao banco de dados já estabelecida e as tabelas criadas, para cada tabela, o script verfica se a tabela já existe no banco de dados, se não, a importa. Assim, se o script for executado com o banco de dados já alimentado, nada será importado.
Figura 2: Visualização do Banco de Dados construído no SQLiteStudio versão 3.3.3
dim_tempo = df_enade_17_18_19[["ID_TEMPO"]].drop_duplicates().reset_index(drop = True)
dim_tempo["ANO"] = dim_tempo.ID_TEMPO
dim_tempo = dim_tempo.set_index("ID_TEMPO").sort_index()
dim_tempo.head(3)
df_enade_17_18_19["ID_CURSO"] = df_enade_17_18_19.groupby(['CO_MODALIDADE','CO_GRUPO']).ngroup()
dim_curso = df_enade_17_18_19[["ID_CURSO",'CO_MODALIDADE','CO_GRUPO']]
dim_curso = dim_curso.drop_duplicates().set_index("ID_CURSO").sort_index()
dicionario_resposta = {0 : "Educação a Distância",
1 : "Educação Presencial",
2 : "Educação a Distância"}
dim_curso = dim_curso.replace({"CO_MODALIDADE": dicionario_resposta})
dicionario_resposta = dict(zip(df_con_17_18_19['Código da Área'], df_con_17_18_19['Área de Avaliação']))
dim_curso = dim_curso.replace({"CO_GRUPO": dicionario_resposta})
dim_curso = dim_curso.rename(columns = {"CO_MODALIDADE" : "MODALIDADE_CURSO",
"CO_GRUPO" : "GRUPO_CURSO"})
dim_curso.head(3)
df_enade_17_18_19["ID_IES_ANO"] = df_enade_17_18_19.groupby(['CO_IES', 'CO_CATEGAD', 'CO_ORGACAD']).ngroup()
dim_ies = df_enade_17_18_19[["ID_IES_ANO",'CO_IES', 'CO_CATEGAD', 'CO_ORGACAD']]
dim_ies = dim_ies.drop_duplicates().set_index("ID_IES_ANO").sort_index()
dicionario_codigos = {10019 : "Centro Federal de Educação Tecnológica",
10020 : " Centro Universitário",
10022 : "Faculdade ",
10026 : "Instituto Federal de Educação, Ciência e Tecnologia",
10028 : "Universidade"}
dim_ies = dim_ies.replace({"CO_ORGACAD": dicionario_codigos})
dicionario_codigos = {1 : "Pública Federal",
2 : "Pública Estadual",
3 : "Pública Municipal",
4 : "Privada com fins lucrativos",
5 : "Privada sem fins lucrativos",
7: "Especial",
118:"Privada com fins lucrativos",
120:"Privada sem fins lucrativos",
121:"Privada sem fins lucrativos",
10005:"Privada com fins lucrativos",
10006:"Privada com fins lucrativos",
10007:"Privada sem fins lucrativos",
10008:"Privada sem fins lucrativos",
10009:"Privada sem fins lucrativos",
17634:"Privada sem fins lucrativos",
93:"Pública Federal",
115:"Pública Estadual",
116:"Pública Municipal",
10001:"Pública Estadual",
10002:"Pública Federal",
10003:"Pública Municipal",
895: "Pública Municipal"}
dim_ies = dim_ies.replace({"CO_CATEGAD": dicionario_codigos})
nome_ies_recence = df_con_17_18_19[['Código da IES','Nome da IES']].drop_duplicates(subset = 'Código da IES',
keep = "last")
dicionario_codigos = dict(zip(nome_ies_recence['Código da IES'], nome_ies_recence['Nome da IES']))
dim_ies = dim_ies.replace({"CO_IES": dicionario_codigos})
nome_ies_recence = df_con_17_18_19[['Código da IES','Nome da IES']].drop_duplicates(subset = 'Código da IES', keep = "last")
dicionario_codigos = dict(zip(nome_ies_recence['Código da IES'], nome_ies_recence['Nome da IES']))
dim_ies = dim_ies.replace({"CO_IES": dicionario_codigos})
dim_ies = dim_ies.rename(columns = {"CO_IES" : "NOME_IES",
"CO_CATEGAD" : "CATEGORIA_IES",
"CO_ORGACAD" : "ORGANIZACAO_IES"})
dim_ies.head(4)
codigos_regiao_cidade = df_enade_17_18_19[["CO_MUNIC_CURSO","CO_REGIAO_CURSO"]].drop_duplicates()
codigos_regiao_cidade = codigos_regiao_cidade.reset_index(drop = True)
dicionario_regiao = {1: "Norte", 2: "Nordeste", 3:"Sudeste", 4:"Sul", 5:"Centro-Oeste"}
codigos_regiao_cidade = codigos_regiao_cidade.replace({"CO_REGIAO_CURSO": dicionario_regiao})
codigos_regiao_cidade = codigos_regiao_cidade.rename(columns = {"CO_REGIAO_CURSO": "REGIAO_CURSO"})
df_cod_cidades = df_cod_cidades.rename(columns = {"CÓDIGO DO MUNICÍPIO": "CO_MUNIC_CURSO",
"NOME DO MUNICÍPIO": "NOME_MUNICIPIO"})
dim_regiao = pd.merge(df_cod_cidades, codigos_regiao_cidade, on = "CO_MUNIC_CURSO").set_index("CO_MUNIC_CURSO")
dim_regiao = dim_regiao.sort_index()
dim_regiao.head(3)
df_enade_17_18_19["ID_PRESENCA"] = df_enade_17_18_19.groupby(['TP_PR_OB_FG','TP_PR_DI_FG','TP_PR_OB_CE','TP_PR_DI_CE']).ngroup()
dicionario_presenca_prova = { 333 : 0,
555 : 1}
dim_presenca = df_enade_17_18_19[['ID_PRESENCA','TP_PR_OB_FG','TP_PR_DI_FG','TP_PR_OB_CE','TP_PR_DI_CE']]
dim_presenca = dim_presenca.drop_duplicates().set_index('ID_PRESENCA').sort_index()
dim_presenca = dim_presenca.replace({'TP_PR_OB_FG': dicionario_presenca_prova,
'TP_PR_DI_FG': dicionario_presenca_prova,
'TP_PR_OB_CE': dicionario_presenca_prova,
'TP_PR_DI_CE': dicionario_presenca_prova})
dim_presenca = dim_presenca.astype(int)
dim_presenca.head()
df_enade_17_18_19.QE_I02 = np.where(df_enade_17_18_19.QE_I02.isna(),
df_enade_17_18_19.QE_I02.value_counts().idxmax(), df_enade_17_18_19.QE_I02)
df_enade_17_18_19.QE_I03 = np.where(df_enade_17_18_19.QE_I03.isna(),
df_enade_17_18_19.QE_I03.value_counts().idxmax(), df_enade_17_18_19.QE_I03)
df_enade_17_18_19["ID_ALUNO_INFO"] = df_enade_17_18_19.groupby(['NU_IDADE','TP_SEXO','CO_TURNO_GRADUACAO',
'QE_I01','QE_I02','QE_I03']).ngroup()
dim_info_aluno = df_enade_17_18_19[["ID_ALUNO_INFO",'NU_IDADE','TP_SEXO','CO_TURNO_GRADUACAO','QE_I01','QE_I02','QE_I03']]
dim_info_aluno = dim_info_aluno.drop_duplicates().set_index("ID_ALUNO_INFO").sort_index()
dicionario_resposta = {"A" : "Solteiro(a)",
"B" : "Casado(a)",
"C" : "Divorciado(a)",
"D" : "Viúvo(a)",
"E" : "Outro"}
dim_info_aluno = dim_info_aluno.replace({"QE_I01": dicionario_resposta})
dicionario_resposta = {"A" : "Branca",
"B" : "Preta",
"C" : "Amarela",
"D" : "Parda",
"E" : "Indígena",
"F" : "Não quero declarar"}
dim_info_aluno = dim_info_aluno.replace({"QE_I02": dicionario_resposta})
dicionario_resposta = {"A" : "Brasileira",
"B" : "Brasileira naturalizada",
"C" : "Estrangeira"}
dim_info_aluno = dim_info_aluno.replace({"QE_I03": dicionario_resposta})
dim_info_aluno = dim_info_aluno.rename(columns = {"QE_I01" : "ESTADO_CIVIL",
"QE_I02" : "RAÇA",
"QE_I03" : "NACIONALIDADE"})
dim_info_aluno.CO_TURNO_GRADUACAO = dim_info_aluno.CO_TURNO_GRADUACAO.astype(int)
dim_info_aluno.head()
df_enade_17_18_19.QE_I17 = np.where(df_enade_17_18_19.QE_I17.isna(),
df_enade_17_18_19.QE_I17.value_counts().idxmax(), df_enade_17_18_19.QE_I17)
df_enade_17_18_19.QE_I18 = np.where(df_enade_17_18_19.QE_I18.isna(),
df_enade_17_18_19.QE_I18.value_counts().idxmax(), df_enade_17_18_19.QE_I18)
df_enade_17_18_19["ID_ALUNO_ENSINO_MEDIO"] = df_enade_17_18_19.groupby(['QE_I17','QE_I18']).ngroup()
dim_ensino_medio = df_enade_17_18_19[["ID_ALUNO_ENSINO_MEDIO",'QE_I17','QE_I18']]
dim_ensino_medio = dim_ensino_medio.drop_duplicates().set_index("ID_ALUNO_ENSINO_MEDIO").sort_index()
dicionario_resposta = {"A" : "Todo em escola pública",
"B" : "Todo em escola privada",
"C" : "Todo no exterior",
"D" : "A maior parte em escola pública",
"E" : "A maior parte em escola privada",
"F" : "Parte no Brasil e parte no exterior"}
dim_ensino_medio = dim_ensino_medio.replace({"QE_I17": dicionario_resposta})
dicionario_resposta = {"A" : "Ensino médio tradicional",
"B" : "Profissionalizante técnico",
"C" : "Profissionalizante magistério",
"D" : "EJA e/ou Supletivo",
"E" : "Outra modalidade"}
dim_ensino_medio = dim_ensino_medio.replace({"QE_I18": dicionario_resposta})
dim_ensino_medio = dim_ensino_medio.rename(columns = {"QE_I17" : "TIPO_ESCOLA_EM",
"QE_I18" : "MODALIDADE_EM"})
dim_ensino_medio.head(3)
df_enade_17_18_19.QE_I04 = np.where(df_enade_17_18_19.QE_I04.isna(),
df_enade_17_18_19.QE_I04.value_counts().idxmax(), df_enade_17_18_19.QE_I04)
df_enade_17_18_19.QE_I05 = np.where(df_enade_17_18_19.QE_I05.isna(),
df_enade_17_18_19.QE_I05.value_counts().idxmax(), df_enade_17_18_19.QE_I05)
df_enade_17_18_19.QE_I21 = np.where(df_enade_17_18_19.QE_I21.isna(),
df_enade_17_18_19.QE_I21.value_counts().idxmax(), df_enade_17_18_19.QE_I21)
df_enade_17_18_19["ID_FORMACAO_FAMILIA"] = df_enade_17_18_19.groupby(['QE_I04','QE_I05','QE_I21']).ngroup()
dim_formacao_familiares = df_enade_17_18_19[["ID_FORMACAO_FAMILIA",'QE_I04','QE_I05','QE_I21']]
dim_formacao_familiares = dim_formacao_familiares.drop_duplicates().set_index("ID_FORMACAO_FAMILIA").sort_index()
dicionario_resposta = {"A" : "Nenhuma",
"B" : "Ensino Fundamental: 1º ao 5º ano (1ª a 4ª série)",
"C" : "Ensino Fundamental: 6º ao 9º ano (5ª a 8ª série)",
"D" : "Ensino Médio",
"E" : "Ensino Superior - Graduação",
"F" : "Pós-graduação"}
dim_formacao_familiares = dim_formacao_familiares.replace({"QE_I04": dicionario_resposta})
dim_formacao_familiares = dim_formacao_familiares.replace({"QE_I05": dicionario_resposta})
dicionario_resposta = {"A" : "Sim",
"B" : "Não"}
dim_formacao_familiares = dim_formacao_familiares.replace({"QE_I21": dicionario_resposta})
dim_formacao_familiares = dim_formacao_familiares.rename(columns = {"QE_I04" : "ESCOLARIZACAO_PAI",
"QE_I05" : "ESCOLARIZACAO_MAE",
"QE_I21" : "FAMILIAR_GRADUADO"})
dim_formacao_familiares.head(5)
df_enade_17_18_19.QE_I24 = np.where(df_enade_17_18_19.QE_I24.isna(), "Não Respondeu", df_enade_17_18_19.QE_I24)
df_enade_17_18_19.QE_I43 = np.where(df_enade_17_18_19.QE_I43.isna(), "Não Respondeu", df_enade_17_18_19.QE_I43)
df_enade_17_18_19.QE_I44 = np.where(df_enade_17_18_19.QE_I44.isna(), "Não Respondeu", df_enade_17_18_19.QE_I44)
df_enade_17_18_19.QE_I52 = np.where(df_enade_17_18_19.QE_I52.isna(), "Não Respondeu", df_enade_17_18_19.QE_I52)
df_enade_17_18_19.QE_I53 = np.where(df_enade_17_18_19.QE_I53.isna(), "Não Respondeu", df_enade_17_18_19.QE_I53)
df_enade_17_18_19["ID_OPORTUNIDADES"] = df_enade_17_18_19.groupby(['QE_I14','QE_I24','QE_I43', 'QE_I44','QE_I52','QE_I53']).ngroup()
dim_oportunidades = df_enade_17_18_19[["ID_OPORTUNIDADES",'QE_I14','QE_I24','QE_I43', 'QE_I44','QE_I52','QE_I53']]
dim_oportunidades = dim_oportunidades.drop_duplicates().set_index("ID_OPORTUNIDADES").sort_index()
dicionario_resposta = {"A" : "Não participei",
"B" : "Programa Ciência sem Fronteiras",
"C" : "Programa de intercâmbio financiado pelo Governo Federal",
"D" : "Programa de intercâmbio financiado pelo Governo Estadual",
"E" : "Programa de intercâmbio da minha instituição",
"F" : "Outro intercâmbio não institucional"}
dim_oportunidades = dim_oportunidades.replace({"QE_I14": dicionario_resposta})
dicionario_resposta = {"A" : "Modalidade presencial",
"B" : "Modalidade semipresencial",
"C" : "Parte presencial e parte semipresencial",
"D" : "A distância",
"E" : "Não"}
dim_oportunidades = dim_oportunidades.replace({"QE_I24": dicionario_resposta})
dicionario_resposta = {1 : "Discordo Totalmente",
2 : "Discordo Parcialmente",
3 : "Nem Discordo Nem Concordo",
4: "Concordo Um Pouco",
5: "Concordo Bastante",
6:"Concordo Totalmente",
7:"Não sei responder",
8:"Não se aplica",
"1" : "Discordo Totalmente",
"2" : "Discordo Parcialmente",
"3" : "Nem Discordo Nem Concordo",
"4": "Concordo Um Pouco",
"5": "Concordo Bastante",
"6":"Concordo Totalmente",
"7":"Não sei responder",
"8":"Não se aplica"}
dim_oportunidades = dim_oportunidades.replace({"QE_I43": dicionario_resposta})
dim_oportunidades = dim_oportunidades.replace({"QE_I44": dicionario_resposta})
dim_oportunidades = dim_oportunidades.replace({"QE_I52": dicionario_resposta})
dim_oportunidades = dim_oportunidades.replace({"QE_I53": dicionario_resposta})
dim_oportunidades = dim_oportunidades.rename(columns = {"QE_I14" : "ATIVIDADES_CURRICURALES_EXTERIOR",
"QE_I24" : "IDIOMA_ESTRANGEIRO",
"QE_I43" : "EXTENSAO_UNIVERSITARIA",
"QE_I44" : "ATIVIDADES_INVESTIGACAO_ACADEMICA",
"QE_I52" : "INTERCAMBIO_ESTAGIO_PAIS",
"QE_I53" : "INTERCAMBIO_ESTAGIO_FORA_DO_PAIS"})
dim_oportunidades.head(4)
df_enade_17_18_19.QE_I07 = np.where(df_enade_17_18_19.QE_I07.isna(),
df_enade_17_18_19.QE_I07.value_counts().idxmax(), df_enade_17_18_19.QE_I07)
df_enade_17_18_19.QE_I08 = np.where(df_enade_17_18_19.QE_I08.isna(),
df_enade_17_18_19.QE_I08.value_counts().idxmax(), df_enade_17_18_19.QE_I08)
df_enade_17_18_19.QE_I10 = np.where(df_enade_17_18_19.QE_I10.isna(),
df_enade_17_18_19.QE_I10.value_counts().idxmax(), df_enade_17_18_19.QE_I10)
df_enade_17_18_19.QE_I12 = np.where(df_enade_17_18_19.QE_I12.isna(),
df_enade_17_18_19.QE_I12.value_counts().idxmax(), df_enade_17_18_19.QE_I12)
df_enade_17_18_19.QE_I15 = np.where(df_enade_17_18_19.QE_I15.isna(),
df_enade_17_18_19.QE_I15.value_counts().idxmax(), df_enade_17_18_19.QE_I15)
dim_aluno_econ = df_enade_17_18_19[['QE_I07','QE_I08','QE_I10','QE_I12','QE_I15']].copy()
dicionario_resposta = {"A" : "Nenhum",
"B" : "Auxílio moradia",
"C" : "Auxílio alimentação",
"D" : "Auxílio moradia e alimentação",
"E" : "Auxílio permanência",
"F" : "Outro tipo de auxílio"}
dim_aluno_econ = dim_aluno_econ.replace({"QE_I12": dicionario_resposta})
dicionario_resposta = {"A" : "Não",
"B" : "Critério étnico-racial",
"C" : "Critério de renda",
"D" : "Critério escola pública ou particular com bolsa de estudos",
"E" : "Combinação de dois ou mais critérios",
"F" : "Outro Critério"}
dim_aluno_econ = dim_aluno_econ.replace({"QE_I15": dicionario_resposta})
dicionario_resposta = {"A" : "Não estou trabalhando.",
"B" : "Trabalho eventualmente.",
"C" : "Trabalho até 20 horas semanais.",
"D" : "Trabalho de 21 a 39 horas semanais.",
"E" : "Trabalho 40 horas semanais ou mais."}
dim_aluno_econ = dim_aluno_econ.replace({"QE_I10": dicionario_resposta})
dicionario_resposta = {"A" : "Até 1,5 salário mínimo",
"B" : "De 1,5 a 3 salários mínimos",
"C" : "De 3 a 4,5 salários mínimos",
"D" : "De 4,5 a 6 salários mínimos",
"E" : "De 6 a 10 salários mínimos",
"F" : "De 10 a 30 salários mínimos",
"G" : "Acima de 30 salários mínimos"}
dim_aluno_econ = dim_aluno_econ.replace({"QE_I08": dicionario_resposta})
dicionario_resposta = {"A" : "Nenhuma",
"B" : "Uma",
"C" : "Duas",
"D" : "Três",
"E" : "Quatro",
"F" : "Cinco",
"G" : "Seis",
"H" : "Sete ou mais"}
dim_aluno_econ = dim_aluno_econ.replace({"QE_I07": dicionario_resposta})
df_enade_17_18_19.QE_I07.value_counts(dropna = False)
dim_aluno_econ["ID_ALUNO_ECONOMICO"] = dim_aluno_econ.groupby(['QE_I07','QE_I08','QE_I10',
'QE_I12','QE_I15']).ngroup()
df_enade_17_18_19["ID_ALUNO_ECONOMICO"] = dim_aluno_econ["ID_ALUNO_ECONOMICO"].copy()
dim_aluno_econ = dim_aluno_econ.drop_duplicates().set_index("ID_ALUNO_ECONOMICO").sort_index()
dim_aluno_econ = dim_aluno_econ.rename(columns = {"QE_I08" : "RENDA_FAMILIAR",
"QE_I10" : "HORAS_TRABALHO",
"QE_I12" : "AUXILIO_RECEBIDO",
"QE_I15" : "ENTROU_POR_COTA",
"QE_I07" : "PESSOAS_MORAM_JUNTO"})
dim_aluno_econ.head(3)
dim_percepcao_prova = df_enade_17_18_19[['CO_RS_I1','CO_RS_I2','CO_RS_I8','CO_RS_I9']].copy()
dicionario_resposta = {"A" : "Muito fácil",
"B" : "Fácil",
"C" : "Médio",
"D" : "Difícil",
"E" : "Muito difícil",
"*" : "Resposta anulada",
"." : "Não respondeu "}
dim_percepcao_prova = dim_percepcao_prova.replace({"CO_RS_I1": dicionario_resposta})
dim_percepcao_prova = dim_percepcao_prova.replace({"CO_RS_I2": dicionario_resposta})
dicionario_resposta = {"A" : "Não estudou a maioria",
"B" : "Estudou alguns, mas nao aprendeu",
"C" : "Estudou a maioria, mas nao aprendeu",
"D" : "Estudou e aprendeu muitos",
"E" : "Estudou e aprendeu todos",
"*" : "Resposta anulada",
"." : "Não respondeu "}
dim_percepcao_prova = dim_percepcao_prova.replace({"CO_RS_I8": dicionario_resposta})
dicionario_resposta = {"A" : 0.5,
"B" : 1.5,
"C" : 2.5,
"D" : 3.5,
"E" : 4.5,
"*" : "Resposta anulada",
"." : "Não respondeu "}
dim_percepcao_prova = dim_percepcao_prova.replace({"CO_RS_I9": dicionario_resposta})
dim_percepcao_prova["ID_PERCEPCAO_PROVA"] = dim_percepcao_prova.groupby(['CO_RS_I1','CO_RS_I2',
'CO_RS_I8','CO_RS_I9']).ngroup()
df_enade_17_18_19["ID_PERCEPCAO_PROVA"] = dim_percepcao_prova["ID_PERCEPCAO_PROVA"].copy()
dim_percepcao_prova = dim_percepcao_prova.drop_duplicates().set_index("ID_PERCEPCAO_PROVA").sort_index()
dim_percepcao_prova = dim_percepcao_prova.rename(columns = {"CO_RS_I1" : "GRAU_DIFICULDADE_FG",
"CO_RS_I2" : "GRAU_DIFICULDADE_CE",
"CO_RS_I8" : "PERCEPCAO_ESTUDO_CONTEUDO",
"CO_RS_I9" : "TEMPO_GASTO_PROVA"})
dim_percepcao_prova.head(4)
colunas_ID = [col for col in df_enade_17_18_19 if col.startswith('ID_') or col.startswith('CO_MUNIC')]
fato_prova = df_enade_17_18_19[colunas_ID + ["NT_GER", "NT_FG", "NT_CE"]]
fato_prova = fato_prova.replace(",", ".", regex=True)
fato_prova[["NT_GER", "NT_FG", "NT_CE"]] = fato_prova[["NT_GER", "NT_FG", "NT_CE"]].astype(float)
fato_prova.index.name = "ID_PROVA"
# fato_prova.head(4)
def nova_conexao(path, nome_bd):
conec_bd = None
try:
conec_bd = sqlite3.connect(path + nome_bd)
except Error as erro:
print(erro)
return 0
finally:
if conec_bd:
conec_bd.close()
return 1
def verifica_tabela_existe(cursor, nome_tabela):
cursor.execute(''' SELECT name FROM sqlite_master WHERE type='table' AND name='{}' '''.format(nome_tabela))
if cursor.fetchone():
return 1
else:
return 0
def insere_tabelas_banco(df, nome_tabela):
path_atual = os.path.dirname(os.path.realpath('__file__')) + "\\" # Diretório corrente
nome_index = df.index.name
df = df.reset_index(drop = False)
# Verifica se já existe tabela referente ao ano do Enade no banco
tabela_existe = verifica_tabela_existe(cursor, nome_tabela)
# Se não existe a tabela, é adicionada ao banco
if not tabela_existe:
dicionario_tipos = dict(df.dtypes)
for key in dicionario_tipos.keys():
if is_integer_dtype(dicionario_tipos[key]):
dicionario_tipos[key] = "integer"
elif is_object_dtype(dicionario_tipos[key]):
dicionario_tipos[key] = "text"
elif is_float_dtype(dicionario_tipos[key]):
dicionario_tipos[key] = "real"
# Transforma o nome da coluna seguido por seu tipo em apenas uma string para cada coluna
# Logo após concatena essas strings utilizando a vírgula como separador
# Sendo o íncio da string final por exemplo:
colunas = ", ".join([key + " " + value for key, value in dicionario_tipos.items()])
print("Criando tabela {} ...".format(nome_tabela), end="\r", flush=True)
# Cria a tabela no banco de dados sqlite passando o nome da tabela, o nome das colunas e seus tipos
comando = f'CREATE TABLE {nome_tabela} ({colunas})'
# comando = 'CREATE TABLE ' + nome_tabela + ' (' + colunas + ')'
cursor.execute('' + comando + '')
if nome_index is not None:
comando = f'CREATE INDEX {nome_index} ON {nome_tabela} ({nome_index})'
cursor.execute('' + comando + '')
print("Tabela {} criada com sucesso no banco {}.".format(nome_tabela, nome_bd), end="\n\n")
print("Importando Microdados para a tabela {} ...".format(nome_tabela), end="\r", flush=True)
# Importa o dataframe com microdados referentes ao no para a tabela no banco de dados
df.to_sql(nome_tabela, conec_bd, if_exists='append', index = False)
conec_bd.commit()
print("Microdados importados para a tabela {} com sucesso.".format(nome_tabela), end="\n\n")
# Se a tabela já existe, nada acontece
else:
print("Tabela {} com Microdados já existe no banco de dados no banco.".format(nome_tabela, nome_bd), end="\n\n")
print("-" * 90)
# Ininia a Conexão
if (nova_conexao(diretorio_atual, nome_bd)):
conec_bd = sqlite3.connect(diretorio_atual + nome_bd)
cursor = conec_bd.cursor()
print("Conexão ao banco '{}' criada com sucesso.\n".format(nome_bd))
print("-" * 90)
conec_bd.commit()
# Nomes das variáveis que contém os dataframes que serão importados
tabelas = [ df for df in dir() if df.startswith('dim_') or df.startswith('fato_')]
# Insere as Tabelas
for nome_tabela in tabelas:
insere_tabelas_banco(globals()[nome_tabela], nome_tabela.upper())
# Encerra a Conexão
conec_bd.close()
print(f"Conexão ao banco '{nome_bd}' encerrada com sucesso.\n")
Foi realizada uma Análise de Dados a partir do Data Warehouse construído. Nessa etapa, alguns dos dados foram utilizados para a realização de análises com o objetivo de avaliar a possível influência de alguns fatores socioeconômicos e geográficos na nota de um aluno.
A análise foi realizada no notebook “02_Analise_Exploratória_Dados.ipynb” utilizando python versão 3.8.8 como linguagem de programação onde foram utlizadas as bibliotecas sqlite3 (para conexão com o banco de dados), researchpy (para gerar tabela de análise), plotly (para visualização). O notebook se encontra com as linhas que geram plots comentadas, pois o arquivo fica muito grande e exige muito de ram se forem descomentadas.
# Python versão 3.8.8
# Windows 10
# biblioteca para interação com o sistema
import os
import shutil
# biblioteca para manipulação de dados
import pandas as pd # versão 1.3.2
import numpy as np # versão 1.20.1
# biblioteca para manipulação de banco de dados sqlite
import sqlite3 # versão 2.6.0
from sqlite3 import Error
import researchpy as rp
# biblioteca para visualização
import plotly.express as px # versão 5.3.1
# import seaborn as sns # versão 0.11.1
import plotly.express as px
import plotly.figure_factory as ff
import warnings
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')
import matplotlib.pyplot as plt # versão 3.3.4
# configuracoes
pd.set_option('display.float_format', lambda x: '%.3f' % x)
# Endereço do diretório onde se encontra o script python
diretorio_atual = os.path.dirname(os.path.realpath('__file__')) + "\\"
# Nome do Banco de Dados de onde serão importadas as tabelas
nome_bd = "Enade_DW.sqlite"
def nova_conexao(path, nome_bd):
conec_bd = None
try:
conec_bd = sqlite3.connect(path + nome_bd)
except Error as erro:
print(erro)
return 0
finally:
if conec_bd:
conec_bd.close()
return 1
# Ininia a Conexão
if (nova_conexao(diretorio_atual, nome_bd)):
conec_bd = sqlite3.connect(diretorio_atual + nome_bd)
cursor = conec_bd.cursor()
print("Conexão ao banco '{}' criada com sucesso.\n".format(nome_bd))
print("-" * 90)
conec_bd.commit()
# Importa tabelas do Banco de Dados
print(f"Importando tabelas do Banco de Dados{nome_bd}...", end="\r", flush=True)
dim_aluno_econ = pd.read_sql_query('SELECT * FROM DIM_ALUNO_ECON ', conec_bd, index_col ='ID_ALUNO_ECONOMICO')
dim_curso = pd.read_sql_query('SELECT * FROM DIM_CURSO ', conec_bd, index_col ='ID_CURSO')
dim_ensino_medio = pd.read_sql_query('SELECT * FROM DIM_ENSINO_MEDIO ', conec_bd, index_col ='ID_ALUNO_ENSINO_MEDIO')
dim_formacao_familiares = pd.read_sql_query('SELECT * FROM DIM_FORMACAO_FAMILIARES ', conec_bd, index_col ='ID_FORMACAO_FAMILIA')
dim_ies = pd.read_sql_query('SELECT * FROM DIM_IES ', conec_bd, index_col ='ID_IES_ANO')
dim_info_aluno = pd.read_sql_query('SELECT * FROM DIM_INFO_ALUNO ', conec_bd, index_col ='ID_ALUNO_INFO')
dim_oportunidades = pd.read_sql_query('SELECT * FROM DIM_OPORTUNIDADES ', conec_bd, index_col ='ID_OPORTUNIDADES')
dim_percepcao_prova = pd.read_sql_query('SELECT * FROM DIM_PERCEPCAO_PROVA ', conec_bd, index_col ='ID_PERCEPCAO_PROVA')
dim_presenca = pd.read_sql_query('SELECT * FROM DIM_PRESENCA ', conec_bd, index_col ='ID_PRESENCA')
dim_regiao = pd.read_sql_query('SELECT * FROM DIM_REGIAO ', conec_bd, index_col ='CO_MUNIC_CURSO')
dim_tempo = pd.read_sql_query('SELECT * FROM DIM_TEMPO ', conec_bd, index_col ='ID_TEMPO')
fato_prova = pd.read_sql_query('SELECT * FROM FATO_PROVA ', conec_bd, index_col ='ID_PROVA')
print(f"Tabelas importadas com Sucesso.\n ")
print("-" * 90)
# Encerra a Conexão
conec_bd.close()
print(f"Conexão ao banco '{nome_bd}' encerrada com sucesso.\n")
df_aluno_info = dim_info_aluno.join(fato_prova.set_index("ID_ALUNO_INFO")[['NT_GER',
'NT_FG','NT_CE']])
df_aluno_info["NT_GER_INTEIRO"] = df_aluno_info["NT_GER"].astype(int)
df_aluno_info.TP_SEXO = df_aluno_info.TP_SEXO.str.replace("F", "Feminino")
df_aluno_info.TP_SEXO = df_aluno_info.TP_SEXO.str.replace("M", "Masculino")
rp.summary_cont(df_aluno_info['NT_GER'].groupby(df_aluno_info['TP_SEXO']))
Tabela 1: tabela com número de casos, média e desvio padrão da nota geral por grupo da coluna “TO_SEXO” que específica o gênero do estudante.
ordem_valores = {"TP_SEXO" : ['Feminino', 'Masculino']}
labels = {"TP_SEXO" : "GÊNERO",
"NT_GER_INTEIRO" : "NOTA_GERAL"}
cores = ['#F04899', '#5187F5']
fig = px.box(df_aluno_info, y="NT_GER_INTEIRO", x = "TP_SEXO", color="TP_SEXO",
boxmode="overlay", labels = labels, category_orders = ordem_valores,
width=800, height=400, color_discrete_sequence = cores)
# fig.show()
Figura 3: Boxplot apresentando a variação de notas para os grupos da coluna “TP_SEXO” que específica o gênero do estudante. É possível ver que a maioria há variação significativa entre os grupos, já que apresentam média, dispersão e outliers muito similiares.
Foi feita a seguinte pergunta “Será que o gênero dos estudantes possui correlação com os desempenhos deles na prova?”, analisando a tabela e gráfico vemos que o número de inscritos do gênero feminino é consideravelmente maior, sendo 732.416 mil estudantes do gênero femino contra 540.806 do gênero masculino como podemos observar na tabela. No entanto, na análise da nota por gênero, vemos que há um desempenho muito semelhante dos estudantes de ambos os gêneros, com médias e desvio padrão muito próximos, assim como os outliers. Dessa forma, podemos concluir que o gênero não tem influência relevante no desempenho do aluno e assim não há evidência significativa para uma falta de investimento na educação em algum gênero específico.
cores = ['#F04899', '#5187F5']
df_aluno_info = df_aluno_info.sort_values(by = "NT_GER_INTEIRO")
df_aluno_info['count'] = df_aluno_info.groupby(['TP_SEXO', 'NT_GER_INTEIRO'])['NT_GER_INTEIRO'].transform('count')
colors = []
fig = px.line(df_aluno_info, x='NT_GER_INTEIRO', color = 'TP_SEXO', y = "count",
labels = labels, category_orders = ordem_valores,
width=800, height=400, color_discrete_sequence = cores)
# fig.show()
Figura 4: gráfico apresentando a distribuição de notas para os grupos da coluna “TP_SEXO” que específica o gênero do estudante. Podemos notar que há mais estudantes inscritos do gênero feminino do que do sexo masculino, contudo a distribuiçào de nota é muito semelhante.
rp.summary_cont(df_aluno_info['NT_GER'].groupby(df_aluno_info['RAÇA']))
Tabela 2: tabela com número de casos, média e desvio padrão da nota geral por grupo da coluna “RAÇA” que específica a raça autodeclarada do estudante.
ordem_valores = {"RAÇA" : ['Amarela', 'Branca','Indígena','Parda','Preta','Não quero declarar']}
cores = ['#19D3F3', '#FFA15A', '#AB63FA', '#00CC96', '#EF553B', '#636EFA']
df_aluno_info = df_aluno_info.sort_values(by = "NT_GER_INTEIRO")
df_aluno_info['count'] = df_aluno_info.groupby(['RAÇA','NT_GER_INTEIRO'])['NT_GER_INTEIRO'].transform('count')
fig = px.line(df_aluno_info, x='NT_GER_INTEIRO', color = 'RAÇA', y = "count",
labels = labels, category_orders = ordem_valores,
width=800, height=400, color_discrete_sequence = cores)
# fig.show()
fig = px.box(df_aluno_info, y="NT_GER_INTEIRO", x = "RAÇA", color="RAÇA",
boxmode="overlay", labels = labels, category_orders = ordem_valores,
width=800, height=400, color_discrete_sequence = cores)
# fig.show()
Para responder a pergunta “A raça ou etnia dos estudante impacta no desempenho na prova?”, foi analisado a tavela acima onde vemos que as pessoas brancas constituem a raça com a maior parcela de inscritos nos anos analisados, onde cerca de metade dos inscritos se autodeclaram brancos. Tal representatividade é refletida quando analisamos as notas. No boxplot abaixo vemos alunos da raça branca tiraram, em média, notas maiores que todas as outras raças, e é a raça que mais apresentam outliers com notas altas. Uma explicação para esse resultado é que as raças parda, preta e indígena são na maior parte pertencentes à classe social baixa, que impacta diretamente no investimento na educação desses estudantes e assim, infelizmente, a raça do estudante tem impacto em seu desempenho.
Figura 5: Boxplot apresentando a variação de notas para os grupos da coluna “RAÇA” que específica o raça autodeclarada do estudante. É possível notar que há uma variação no desempenho do aluno dependendo de sua raça autodeclarada, com alunos autodeclarados brancos apresentando melhor desempenho.
df_aluno_info[["NU_IDADE"]].describe()
>
Tabela 3: Descrição coluna Idade
Temos que os inscritos possuem idades bem variadas indo desde 16 anos até 87, todavia, 75% possuem até 31 anos, o que indica que poucos são os graduandos concluites acima da faixa dos 30. A fim de responder o questionamento “A idade dos estudante possui impacto nos desempenhos do Enade?”, foi elaborado uma melhor visualização da relação da Idade com a nota, ao invés de plotar cada amostra no gráfico de dispersão, os dados foram agrupados por idade e assim calcuado a nota média de cada idade para então serem plotados. Vemos então pelo gráfico que a Idade possui uma correlação negativa, onde a medida que a idade vai aumentando, a nota média vai tendendo a cair, com estudantes entre 35 e 55 anos apresentendo médias muito próximas, porém os inscritos com com 56 ou mais apresentam médias bem mais dispersas e mais baixa em sua maioria.
df_aluno_info['MEDIA_NOTA_GERAL'] = df_aluno_info.groupby(['NU_IDADE'])['NT_GER'].transform('mean')
labels = { "NU_IDADE" : "IDADE"}
fig = px.scatter(
df_aluno_info, x='NU_IDADE', y='MEDIA_NOTA_GERAL', opacity=0.65,
trendline='ols', trendline_color_override='red', labels = labels, width=800, height=400)
# fig.show()
df_aluno_info[["NU_IDADE", "NT_GER"]].corr()
Tabela 4: Correlação entre a variável idade e a nota geral
df_regiao_tempo = dim_regiao.join(fato_prova.set_index("CO_MUNIC_CURSO")[['ID_TEMPO','NT_GER',
'NT_FG','NT_CE']])
df_tempo = dim_tempo.reset_index()
df_regiao_tempo = df_regiao_tempo.reset_index()
df_regiao_tempo = df_regiao_tempo.merge(df_tempo, how = "left").drop("ID_TEMPO", axis = 1)
rp.summary_cont(df_regiao_tempo['NT_GER'].groupby(df_regiao_tempo['UF']))
Tabela 5: tabela com número de casos, média e desvio padrão da nota geral por grupo da coluna “UF” que específica o Estado em que o curso que o Aluno realiza é oferecido.
rp.summary_cont(df_regiao_tempo['NT_GER'].groupby(df_regiao_tempo['REGIAO_CURSO']))
Figura 6: tabela com número de casos, média e desvio padrão da nota geral por grupo da coluna “REGIAO_CURSO” que específica a região em que o curso que o Aluno realiza é oferecido.
df_regiao_tempo["NT_GER_INTEIRO"] = df_regiao_tempo["NT_GER"].astype(int)
df_regiao_tempo['Count'] = df_regiao_tempo.groupby(['UF', 'ANO'])['NT_GER_INTEIRO'].transform('count')
df_regiao_tempo['MEDIA_NOTA_GERAL'] = df_regiao_tempo.groupby(['UF', 'ANO'])['NT_GER_INTEIRO'].transform('mean')
UF_ordem_alfabetica = list(df_regiao_tempo.UF.sort_values().drop_duplicates())
ano_ordem = list(df_regiao_tempo.ANO.sort_values().drop_duplicates())
regiao_ordem = list(df_regiao_tempo.REGIAO_CURSO.sort_values().drop_duplicates())
ordem_valores = {"ANO" : ano_ordem,
"UF" : UF_ordem_alfabetica,
"REGIAO_CURSO" : regiao_ordem}
fig = px.scatter(df_regiao_tempo, y="MEDIA_NOTA_GERAL", x = "UF" , animation_frame="ANO", animation_group="UF",
size="Count", color="REGIAO_CURSO", hover_name="REGIAO_CURSO", range_y=[35,50],
category_orders = ordem_valores)
# fig.show()
Figura 7: Boxplot apresentando a variação de notas para os grupos da coluna “REGIAO_CURSO” que específica a região em que o curso que o Aluno realiza é oferecido. Podemos visualizar que o desempenho dos alunos tendem a variar de acordo com a Região.
Analisando a tabela e o gráfico de boxplot acima, podemos responder a questão “A região onde o curso é oferecido possui alguma influência nas notas das provas?” onde vemos uma diferença no desempenho dos estudantes das regiões, em que estudantes das regiões Sudeste e Sul apresentam melhores resultados e os da região Norte não vão tão bem na prova.
ordem_valores = {"UF" : UF_ordem_alfabetica}
ordem = ['DF', 'GO', 'MS', 'MT', 'AL', 'BA', 'CE', 'MA', 'PB', 'PE', 'PI', 'RN',
'SE', 'AC', 'AM', 'AP', 'PA', 'RO', 'RR', 'TO', 'ES', 'MG', 'RJ', 'SP',
'PR', 'RS', 'SC']
df_regiao_tempo.UF = df_regiao_tempo.UF.astype("category")
df_regiao_tempo.UF = df_regiao_tempo.UF.cat.set_categories(ordem)
df_regiao_tempo.head(4)
ordem = ['DF', 'GO', 'MS', 'MT', 'AL', 'BA', 'CE', 'MA', 'PB', 'PE', 'PI', 'RN',
'SE', 'AC', 'AM', 'AP', 'PA', 'RO', 'RR', 'TO', 'ES', 'MG', 'RJ', 'SP',
'PR', 'RS', 'SC']
ordem_valores = {"UF" : ordem,
"REGIAO_CURSO" : regiao_ordem}
fig = px.box(df_regiao_tempo, y="NT_GER_INTEIRO", x = "UF", color="REGIAO_CURSO",
boxmode="overlay", labels = labels, width=800, height=400,
category_orders = ordem_valores)
# fig.show()
Ao aumentar a granuralidade dos dados e analisar as notas por estado, vemos que a nota média por estado, podemos notar que se destacam os estados da Região Sudeste, Rio Grande do Sul, Distrito Federal com melhores desempenhos na nota. Tal observação sugere que boa parcela dos investimentos sejam direcionados para os estados dessa região.
Figura 8: Boxplot apresentando a variação de notas para os grupos da coluna “UF” que específica o Estado em que o curso que o Aluno realiza é oferecido. Podemos visualizar que o desempenho dos alunos também tende a variar de acordo com a UF, não só com a Região, já que estados de uma mesma região apresentam variação nas notas diferente.
ordem = ['DF', 'GO', 'MS', 'MT', 'AL', 'BA', 'CE', 'MA', 'PB', 'PE', 'PI', 'RN',
'SE', 'AC', 'AM', 'AP', 'PA', 'RO', 'RR', 'TO', 'ES', 'MG', 'RJ', 'SP',
'PR', 'RS', 'SC']
ordem_valores = {"UF" : UF_ordem_alfabetica,
"REGIAO_CURSO" : regiao_ordem}
fig = px.box(df_regiao_tempo, y="NT_GER_INTEIRO", x = "UF", color="REGIAO_CURSO",
boxmode="overlay", labels = labels, width=800, height=400,
category_orders = ordem_valores)
# fig.show()
fig = px.box(df_regiao_tempo, y="NT_GER_INTEIRO", x = "REGIAO_CURSO", color="REGIAO_CURSO",
boxmode="overlay", labels = labels, width=800, height=400,
category_orders = ordem_valores)
# fig.show()
df_economico = dim_aluno_econ.join(fato_prova.set_index("ID_ALUNO_ECONOMICO")[['ID_TEMPO','NT_GER',
'NT_FG','NT_CE']])
# Ordem dos valores na coluna RENDA_FAMILIAR
ordem = ['Até 1,5 salário mínimo',
'De 1,5 a 3 salários mínimos',
'De 3 a 4,5 salários mínimos',
'De 4,5 a 6 salários mínimos',
'De 6 a 10 salários mínimos',
'De 10 a 30 salários mínimos',
'Acima de 30 salários mínimos']
df_economico.RENDA_FAMILIAR = df_economico.RENDA_FAMILIAR.astype("category")
df_economico.RENDA_FAMILIAR = df_economico.RENDA_FAMILIAR.cat.set_categories(ordem)
rp.summary_cont(df_economico['NT_GER'].groupby(df_economico['RENDA_FAMILIAR']))
Tabela 7: tabela com número de casos, média e desvio padrão da nota geral por grupo da coluna “RENDA_FAMILIAR” que específica a Renda Familiar média declarada pelo aluno.
Por último, foi feito o quesionamento “Será que a Renda Familiar do estudante possui correlação com sua nota?”. Através da tabela acima, podemos ver que a maior parcela dos inscritos possuem renda familiar de até 4.5 salários mínimos. Contudo, ao olharmos para o desempenho desses grupos no boxplot vemos uma clara tendência de aumento na nota a medida que renda familiar aumenta. Uma possível explição para essa situação é o fato de que quanto maior é o poder aquisitivo, maior são as oportunidades de investrem em educação. Dessa forma, podemos afirmar que a renda familiar é um fator que possui uma correlação positiva com a nota no ENADE que também pode ser observada no boxplot a seguir.
ordem_valores = {"RENDA_FAMILIAR" : ['Até 1,5 salário mínimo',
'De 1,5 a 3 salários mínimos',
'De 3 a 4,5 salários mínimos',
'De 4,5 a 6 salários mínimos',
'De 6 a 10 salários mínimos',
'De 10 a 30 salários mínimos',
'Acima de 30 salários mínimos']}
labels = {"NT_GER_INTEIRO" : "NOTA GERAL",
"RENDA_FAMILIAR": "RENDA FAMILIAR"}
fig = px.box(df_economico, y="NT_GER", x = "RENDA_FAMILIAR", color="RENDA_FAMILIAR",
boxmode="overlay", labels = labels, category_orders = ordem_valores, width=800, height=400)
# fig.show()
Figura 9: Boxplot apresentando a variação de notas para os grupos da coluna “RENDA_FAMILIAR” que específica a Renda Familiar média declarada pelo aluno. Podemos ver que a renda familiar do aluno é um fator que influencia seu desempenho, em que no geral, quanto maior a renda, melhor é o desempenho.
Para esse trabalho foi elaborado um modelo de predição que com base alguns dos dados fornecidos pelo estudante (todos os selecionados para compor as dimensões do modelo estrela desenvolvido) classifique se o estudante tirou uma nota acima da nota média do ano em que prestou a prova. Primeiramente, calculou-se a nota média de cada ano utlizando toda a base, com o conhecimento desses valores, criou-se a coluna target que indica se a nota geral do estudante é maior do que a nota média do ano, assim, se o estudante obteve uma nota maior do que a nota geral média do ano em que realizou a prova, a variável será igual à 1, caso contrário, será 0. O modelo tem então o objetivo de classificar essa variável como 1 ou 0 para cada estudante, classificando assim seu desempenho.
O modelo foi implementado na linguagem python e pode ser visto no scrpit “03_Aprendizado_Random_Forest_Nota.ipynb”. O algoritmo escolhido para compor o modelo foi o Random Forest com parâmetros iguais a máxima profundadade = 12, número de árvores = 5. O moledo foi treinado com 90% dos dados separados de forma aleatória e testado com os outros 10%. As estísticas e matriz de confusão da predição podem ser vistas na imagens abaixo.
Como grande parde das variáveis eram categóricas e todas as variáveis de entrada para o modelo necessitam ser numéricas, foi feita uma conversão dos dados onde variáveis que só assumiam valores “Sim” ou “Não” foram transformadas em booleanda, variáveis que apresentavam alguma informação numérica ou níveis de intensidade de forma categórica foram interpretadas numéricamente como a coluna de Renda Familiar e por último, todas as as que sobraram foram convertidas utilizando o método Mean Encoding.
# Python versão 3.8.8
# Windows 10
# biblioteca para interação com o sistema
import os
import shutil
# biblioteca para manipulação de dados
import pandas as pd # versão 1.3.2
import numpy as np # versão 1.20.1
# biblioteca para manipulação de banco de dados sqlite
import sqlite3 # versão 2.6.0
from sqlite3 import Error
import researchpy as rp
# biblioteca para visualização
import plotly.express as px # versão 5.3.1
import seaborn as sns # versão 0.11.1
import plotly.express as px
import plotly.figure_factory as ff
import warnings
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')
import matplotlib.pyplot as plt # versão 3.3.4
from matplotlib import rcParams
%matplotlib inline
from sklearn.tree import DecisionTreeClassifier # Importa o classificador de árvore de decisão
from sklearn import metrics #Importa métrica para calcular acurácia - módulo do scikit-learn
from sklearn.model_selection import train_test_split
from sklearn.tree import export_graphviz
from sklearn.model_selection import KFold
from IPython.display import Image
#bibliotecas necessárias
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from math import sqrt
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error,mean_absolute_error
from sklearn.metrics import classification_report
from sklearn.datasets import make_classification
from sklearn.metrics import plot_confusion_matrix
from sklearn.svm import SVC
from sklearn import metrics
from category_encoders import TargetEncoder
# Endereço do diretório onde se encontra o script python
diretorio_atual = os.path.dirname(os.path.realpath('__file__')) + "\\"
# Nome do Banco de Dados de onde serão importadas as tabelas
nome_bd = "Enade_DW.sqlite"
def nova_conexao(path, nome_bd):
conec_bd = None
try:
conec_bd = sqlite3.connect(path + nome_bd)
except Error as erro:
print(erro)
return 0
finally:
if conec_bd:
conec_bd.close()
return 1
#Definindo função para plotar grafico de comparação
def grafico(previsto,real,nome):
previsto = np.array(previsto)
real = np.array(real)
mape = mean_absolute_error(real,previsto)
y1 = previsto[:50]
x1 = range(len(y1))
y2 = real[:50]
x2 = range(len(y2))
plt.title('Gráfico de Predições:'+nome)
plt.xlabel('mape: '+str(mape))
plt.ylabel('Valores')
plt.plot(x1,y1,color='#D90286',linestyle='--',label='Predita')
plt.plot(x2,y2,color='#0864AD',linestyle='-.', label = 'Esperada')
plt.legend()
plt.show()
# Ininia a Conexão
if (nova_conexao(diretorio_atual, nome_bd)):
conec_bd = sqlite3.connect(diretorio_atual + nome_bd)
cursor = conec_bd.cursor()
print("Conexão ao banco '{}' criada com sucesso.\n".format(nome_bd))
print("-" * 90)
conec_bd.commit()
# Importa tabelas do Banco de Dados
print(f"Importando tabelas do Banco de Dados{nome_bd}...", end="\r", flush=True)
dim_aluno_econ = pd.read_sql_query('SELECT * FROM DIM_ALUNO_ECON ', conec_bd, index_col ='ID_ALUNO_ECONOMICO')
dim_curso = pd.read_sql_query('SELECT * FROM DIM_CURSO ', conec_bd, index_col ='ID_CURSO')
dim_ensino_medio = pd.read_sql_query('SELECT * FROM DIM_ENSINO_MEDIO ', conec_bd, index_col ='ID_ALUNO_ENSINO_MEDIO')
dim_formacao_familiares = pd.read_sql_query('SELECT * FROM DIM_FORMACAO_FAMILIARES ', conec_bd, index_col ='ID_FORMACAO_FAMILIA')
dim_ies = pd.read_sql_query('SELECT * FROM DIM_IES ', conec_bd, index_col ='ID_IES_ANO')
dim_info_aluno = pd.read_sql_query('SELECT * FROM DIM_INFO_ALUNO ', conec_bd, index_col ='ID_ALUNO_INFO')
dim_oportunidades = pd.read_sql_query('SELECT * FROM DIM_OPORTUNIDADES ', conec_bd, index_col ='ID_OPORTUNIDADES')
dim_percepcao_prova = pd.read_sql_query('SELECT * FROM DIM_PERCEPCAO_PROVA ', conec_bd, index_col ='ID_PERCEPCAO_PROVA')
dim_presenca = pd.read_sql_query('SELECT * FROM DIM_PRESENCA ', conec_bd, index_col ='ID_PRESENCA')
dim_regiao = pd.read_sql_query('SELECT * FROM DIM_REGIAO ', conec_bd, index_col ='CO_MUNIC_CURSO')
dim_tempo = pd.read_sql_query('SELECT * FROM DIM_TEMPO ', conec_bd, index_col ='ID_TEMPO')
fato_prova = pd.read_sql_query('SELECT * FROM FATO_PROVA ', conec_bd, index_col ='ID_PROVA')
print(f"Tabelas importadas com Sucesso.\n ")
print("-" * 90)
# Encerra a Conexão
conec_bd.close()
print(f"Conexão ao banco '{nome_bd}' encerrada com sucesso.\n")
# União de todas as dimensões com a Tabela Fato
df_completo = fato_prova.merge(dim_info_aluno, how = "left", left_on = "ID_ALUNO_INFO" , right_index = True)
df_completo = df_completo.merge(dim_aluno_econ, how = 'left', left_on = 'ID_ALUNO_ECONOMICO' , right_index = True)
df_completo = df_completo.merge(dim_curso, how = 'left', left_on = 'ID_CURSO' , right_index = True)
df_completo = df_completo.merge(dim_ensino_medio, how = 'left', left_on = 'ID_ALUNO_ENSINO_MEDIO' , right_index = True)
df_completo = df_completo.merge(dim_formacao_familiares, how = 'left', left_on = 'ID_FORMACAO_FAMILIA' , right_index = True)
df_completo = df_completo.merge(dim_ies, how = 'left', left_on = 'ID_IES_ANO' , right_index = True)
df_completo = df_completo.merge(dim_oportunidades, how = 'left', left_on = 'ID_OPORTUNIDADES' , right_index = True)
df_completo = df_completo.merge(dim_percepcao_prova, how = 'left', left_on = 'ID_PERCEPCAO_PROVA' , right_index = True)
df_completo = df_completo.merge(dim_presenca, how = 'left', left_on = 'ID_PRESENCA' , right_index = True)
df_completo = df_completo.merge(dim_regiao, how = 'left', left_on = 'CO_MUNIC_CURSO' , right_index = True)
df_completo = df_completo.merge(dim_tempo, how = 'left', left_on = 'ID_TEMPO' , right_index = True)
# Remoção das colunas Chaves
df_completo = df_completo.drop(['ID_ALUNO_ECONOMICO',
'ID_CURSO',
'ID_ALUNO_ENSINO_MEDIO',
'ID_FORMACAO_FAMILIA',
'ID_IES_ANO',
'ID_ALUNO_INFO',
'ID_OPORTUNIDADES',
'ID_PERCEPCAO_PROVA',
'ID_PRESENCA',
'CO_MUNIC_CURSO',
'ID_TEMPO'], axis = 1)
df_completo.shape
df_completo_backup = df_completo.copy()
from sklearn.ensemble import RandomForestClassifier
df_completo = df_completo_backup.copy()
dicionario_resposta = {'Não respondeu ' : 1.5,
"Resposta anulada": 2}
df_completo = df_completo.replace({"TEMPO_GASTO_PROVA": dicionario_resposta})
df_completo.TEMPO_GASTO_PROVA = df_completo.TEMPO_GASTO_PROVA.astype(float)
dicionario_resposta = {'Trabalho 40 horas semanais ou mais.' : 40,
'Trabalho até 20 horas semanais.': 20,
'Não estou trabalhando.': 0,
'Trabalho de 21 a 39 horas semanais.': 30,
'Trabalho eventualmente.': 5
}
df_completo = df_completo.replace({"HORAS_TRABALHO": dicionario_resposta})
df_completo.HORAS_TRABALHO = df_completo.HORAS_TRABALHO.astype(float)
dicionario_resposta = {'Resposta anulada': 0,
'Muito difícil': 0,
'Difícil': 3,
'Não respondeu ': 2,
'Médio': 5,
'Fácil': 6,
'Muito fácil': 1
}
df_completo = df_completo.replace({"GRAU_DIFICULDADE_CE": dicionario_resposta})
df_completo.GRAU_DIFICULDADE_CE = df_completo.GRAU_DIFICULDADE_CE.astype(float)
df_completo = df_completo.replace({"GRAU_DIFICULDADE_FG": dicionario_resposta})
df_completo.GRAU_DIFICULDADE_FG = df_completo.GRAU_DIFICULDADE_FG.astype(float)
dicionario_resposta = {'Nenhuma': 0,
'Uma': 1,
'Duas': 2,
'Três': 3,
'Quatro': 4,
'Cinco': 5,
'Seis': 6,
'Sete ou mais': 9
}
df_completo = df_completo.replace({"PESSOAS_MORAM_JUNTO": dicionario_resposta})
df_completo.PESSOAS_MORAM_JUNTO = df_completo.PESSOAS_MORAM_JUNTO.astype(float)
dicionario_resposta = {'Até 1,5 salário mínimo': 0.8,
'De 1,5 a 3 salários mínimos': 2,
'De 3 a 4,5 salários mínimos': 3.5,
'De 4,5 a 6 salários mínimos': 5,
'De 6 a 10 salários mínimos': 7.5,
'De 10 a 30 salários mínimos': 20,
'Acima de 30 salários mínimos': 35
}
df_completo = df_completo.replace({"RENDA_FAMILIAR": dicionario_resposta})
df_completo.RENDA_FAMILIAR = df_completo.RENDA_FAMILIAR.astype(float)
df_completo["RENDA_PER_CAPITA"] = df_completo.RENDA_FAMILIAR/(df_completo.PESSOAS_MORAM_JUNTO +1)
df_completo['FAMILIAR_GRADUADO'] = np.where(df_completo['FAMILIAR_GRADUADO'] == 'Sim', 1, 0)
df_completo['MODALIDADE_CURSO'] = np.where(df_completo['MODALIDADE_CURSO'] == 'Educação Presencial', 1, 0)
df_completo.MODALIDADE_CURSO = df_completo.MODALIDADE_CURSO.astype(int)
df_completo['NACIONALIDADE'] = np.where(df_completo['NACIONALIDADE'] == 'Brasileira', 1, 0)
df_completo.NACIONALIDADE = df_completo.NACIONALIDADE.astype(int)
# Enconding da coluna TP_SEXO
encoder = TargetEncoder()
df_completo['TP_SEXO'] = encoder.fit_transform(df_completo['TP_SEXO'], df_completo['NT_GER'])
df_completo['TP_SEXO'] = encoder.fit_transform(df_completo['TP_SEXO'], df_completo['NT_GER'])
# Enconding da coluna ESTADO_CIVIL
encoder = TargetEncoder()
df_completo['ESTADO_CIVIL'] = encoder.fit_transform(df_completo['ESTADO_CIVIL'], df_completo['NT_GER'])
df_completo['ESTADO_CIVIL'] = encoder.fit_transform(df_completo['ESTADO_CIVIL'], df_completo['NT_GER'])
# Enconding da coluna RAÇA
encoder = TargetEncoder()
df_completo['RAÇA'] = encoder.fit_transform(df_completo['RAÇA'], df_completo['NT_GER'])
df_completo['RAÇA'] = encoder.fit_transform(df_completo['RAÇA'], df_completo['NT_GER'])
# Enconding da coluna AUXILIO_RECEBIDO
encoder = TargetEncoder()
df_completo['AUXILIO_RECEBIDO'] = encoder.fit_transform(df_completo['AUXILIO_RECEBIDO'], df_completo['NT_GER'])
df_completo['AUXILIO_RECEBIDO'] = encoder.fit_transform(df_completo['AUXILIO_RECEBIDO'], df_completo['NT_GER'])
# Enconding da coluna ENTROU_POR_COTA
encoder = TargetEncoder()
df_completo['ENTROU_POR_COTA'] = encoder.fit_transform(df_completo['ENTROU_POR_COTA'], df_completo['NT_GER'])
df_completo['ENTROU_POR_COTA'] = encoder.fit_transform(df_completo['ENTROU_POR_COTA'], df_completo['NT_GER'])
# Enconding da coluna GRUPO_CURSO
encoder = TargetEncoder()
df_completo['GRUPO_CURSO'] = encoder.fit_transform(df_completo['GRUPO_CURSO'], df_completo['NT_GER'])
df_completo['GRUPO_CURSO'] = encoder.fit_transform(df_completo['GRUPO_CURSO'], df_completo['NT_GER'])
# Enconding da coluna TIPO_ESCOLA_EM
encoder = TargetEncoder()
df_completo['TIPO_ESCOLA_EM'] = encoder.fit_transform(df_completo['TIPO_ESCOLA_EM'], df_completo['NT_GER'])
df_completo['TIPO_ESCOLA_EM'] = encoder.fit_transform(df_completo['TIPO_ESCOLA_EM'], df_completo['NT_GER'])
# Enconding da coluna MODALIDADE_EM
encoder = TargetEncoder()
df_completo['MODALIDADE_EM'] = encoder.fit_transform(df_completo['MODALIDADE_EM'], df_completo['NT_GER'])
df_completo['MODALIDADE_EM'] = encoder.fit_transform(df_completo['MODALIDADE_EM'], df_completo['NT_GER'])
# Enconding da coluna ESCOLARIZACAO_PAI
encoder = TargetEncoder()
df_completo['ESCOLARIZACAO_PAI'] = encoder.fit_transform(df_completo['ESCOLARIZACAO_PAI'], df_completo['NT_GER'])
df_completo['ESCOLARIZACAO_PAI'] = encoder.fit_transform(df_completo['ESCOLARIZACAO_PAI'], df_completo['NT_GER'])
# Enconding da coluna ESCOLARIZACAO_MAE
encoder = TargetEncoder()
df_completo['ESCOLARIZACAO_MAE'] = encoder.fit_transform(df_completo['ESCOLARIZACAO_MAE'], df_completo['NT_GER'])
df_completo['ESCOLARIZACAO_MAE'] = encoder.fit_transform(df_completo['ESCOLARIZACAO_MAE'], df_completo['NT_GER'])
# Enconding da coluna NOME_IES
encoder = TargetEncoder()
df_completo['NOME_IES'] = encoder.fit_transform(df_completo['NOME_IES'], df_completo['NT_GER'])
df_completo['NOME_IES'] = encoder.fit_transform(df_completo['NOME_IES'], df_completo['NT_GER'])
# Enconding da coluna CATEGORIA_IES
encoder = TargetEncoder()
df_completo['CATEGORIA_IES'] = encoder.fit_transform(df_completo['CATEGORIA_IES'], df_completo['NT_GER'])
df_completo['CATEGORIA_IES'] = encoder.fit_transform(df_completo['CATEGORIA_IES'], df_completo['NT_GER'])
# Enconding da coluna ORGANIZACAO_IES
encoder = TargetEncoder()
df_completo['ORGANIZACAO_IES'] = encoder.fit_transform(df_completo['ORGANIZACAO_IES'], df_completo['NT_GER'])
df_completo['ORGANIZACAO_IES'] = encoder.fit_transform(df_completo['ORGANIZACAO_IES'], df_completo['NT_GER'])
# Enconding da coluna ATIVIDADES_CURRICURALES_EXTERIOR
encoder = TargetEncoder()
df_completo['ATIVIDADES_CURRICURALES_EXTERIOR'] = encoder.fit_transform(df_completo['ATIVIDADES_CURRICURALES_EXTERIOR'], df_completo['NT_GER'])
df_completo['ATIVIDADES_CURRICURALES_EXTERIOR'] = encoder.fit_transform(df_completo['ATIVIDADES_CURRICURALES_EXTERIOR'], df_completo['NT_GER'])
# Enconding da coluna IDIOMA_ESTRANGEIRO
encoder = TargetEncoder()
df_completo['IDIOMA_ESTRANGEIRO'] = encoder.fit_transform(df_completo['IDIOMA_ESTRANGEIRO'], df_completo['NT_GER'])
df_completo['IDIOMA_ESTRANGEIRO'] = encoder.fit_transform(df_completo['IDIOMA_ESTRANGEIRO'], df_completo['NT_GER'])
# Enconding da coluna EXTENSAO_UNIVERSITARIA
encoder = TargetEncoder()
df_completo['EXTENSAO_UNIVERSITARIA'] = encoder.fit_transform(df_completo['EXTENSAO_UNIVERSITARIA'], df_completo['NT_GER'])
df_completo['EXTENSAO_UNIVERSITARIA'] = encoder.fit_transform(df_completo['EXTENSAO_UNIVERSITARIA'], df_completo['NT_GER'])
# Enconding da coluna ATIVIDADES_INVESTIGACAO_ACADEMICA
encoder = TargetEncoder()
df_completo['ATIVIDADES_INVESTIGACAO_ACADEMICA'] = encoder.fit_transform(df_completo['ATIVIDADES_INVESTIGACAO_ACADEMICA'], df_completo['NT_GER'])
df_completo['ATIVIDADES_INVESTIGACAO_ACADEMICA'] = encoder.fit_transform(df_completo['ATIVIDADES_INVESTIGACAO_ACADEMICA'], df_completo['NT_GER'])
# Enconding da coluna INTERCAMBIO_ESTAGIO_PAIS
encoder = TargetEncoder()
df_completo['INTERCAMBIO_ESTAGIO_PAIS'] = encoder.fit_transform(df_completo['INTERCAMBIO_ESTAGIO_PAIS'], df_completo['NT_GER'])
df_completo['INTERCAMBIO_ESTAGIO_PAIS'] = encoder.fit_transform(df_completo['INTERCAMBIO_ESTAGIO_PAIS'], df_completo['NT_GER'])
# Enconding da coluna INTERCAMBIO_ESTAGIO_FORA_DO_PAIS
encoder = TargetEncoder()
df_completo['INTERCAMBIO_ESTAGIO_FORA_DO_PAIS'] = encoder.fit_transform(df_completo['INTERCAMBIO_ESTAGIO_FORA_DO_PAIS'], df_completo['NT_GER'])
df_completo['INTERCAMBIO_ESTAGIO_FORA_DO_PAIS'] = encoder.fit_transform(df_completo['INTERCAMBIO_ESTAGIO_FORA_DO_PAIS'], df_completo['NT_GER'])
# Enconding da coluna PERCEPCAO_ESTUDO_CONTEUDO
encoder = TargetEncoder()
df_completo['PERCEPCAO_ESTUDO_CONTEUDO'] = encoder.fit_transform(df_completo['PERCEPCAO_ESTUDO_CONTEUDO'], df_completo['NT_GER'])
df_completo['PERCEPCAO_ESTUDO_CONTEUDO'] = encoder.fit_transform(df_completo['PERCEPCAO_ESTUDO_CONTEUDO'], df_completo['NT_GER'])
# Enconding da coluna NOME_MUNICIPIO
encoder = TargetEncoder()
df_completo['NOME_MUNICIPIO'] = encoder.fit_transform(df_completo['NOME_MUNICIPIO'], df_completo['NT_GER'])
df_completo['NOME_MUNICIPIO'] = encoder.fit_transform(df_completo['NOME_MUNICIPIO'], df_completo['NT_GER'])
# Enconding da coluna UF
encoder = TargetEncoder()
df_completo['UF'] = encoder.fit_transform(df_completo['UF'], df_completo['NT_GER'])
df_completo['UF'] = encoder.fit_transform(df_completo['UF'], df_completo['NT_GER'])
# Enconding da coluna REGIAO_CURSO
encoder = TargetEncoder()
df_completo['REGIAO_CURSO'] = encoder.fit_transform(df_completo['REGIAO_CURSO'], df_completo['NT_GER'])
df_completo['REGIAO_CURSO'] = encoder.fit_transform(df_completo['REGIAO_CURSO'], df_completo['NT_GER'])
df_completo['NOTA_MEDIA_ANO'] = df_completo.groupby(['ANO'])['NT_GER'].transform('mean')
df_completo["MAIOR_QUE_NOTA_MEDIA_ANO"] = df_completo['NT_GER'] > df_completo['NOTA_MEDIA_ANO']
dataset_modelo = df_completo.select_dtypes(include=["number","bool_"]).drop(['NT_FG', 'NT_CE', 'NT_GER',
'PESSOAS_MORAM_JUNTO', 'RENDA_FAMILIAR',
'NOTA_MEDIA_ANO'], axis = 1).copy()
y = dataset_modelo["MAIOR_QUE_NOTA_MEDIA_ANO"]
dataset_modelo = dataset_modelo.drop("MAIOR_QUE_NOTA_MEDIA_ANO",
axis = 1)
#split de dados
x_treino, x_teste, y_treino, y_teste = train_test_split(dataset_modelo, y, test_size = 0.1, shuffle = True)
rfc = RandomForestClassifier(n_estimators = 5, random_state=0, criterion = "entropy", max_depth = 11)
rfc.fit(x_treino, y_treino)
y_pred = rfc.predict(x_teste)
acuracia = metrics.accuracy_score(y_teste, y_pred)
print(f"A Acurácia do modelo é de: {acuracia}")
precisao = metrics.precision_score(y_teste, y_pred)
print(f"A Precisão do modelo é de: {precisao}")
plot_confusion_matrix(rfc, x_teste, y_teste, values_format = '.0f')
plt.show()
plt.rcParams["figure.figsize"] = (80,14)
Figura 10: Matriz de Confusão do Modelo de Random Forest.
print(classification_report(y_teste, y_pred))
Figura 11: Estatísticas da predição realizada pelo Modelo de Random Forest.
plt.rcParams["figure.figsize"] = (8,6)
metrics.plot_roc_curve(rfc, x_teste, y_teste)
Figura 12: Curva ROC do Modelo.
Vemos que o modelo obteve uma precisão de 70% e uma acurácia de 69% o que implica que o desempenho do estudante pode ser explicado em boa parte pelas informções acadêmicas, socioeconômias e geográficas do estudante. A fim de observar o quanto cada variável impacta no desempenho do estudante, foi elaborado o gráfico abaixo que apresenta a importância de cada feature para o modelo.
tmp = pd.DataFrame({'Feature': dataset_modelo.columns.to_list(),
'Importância da feature': rfc.feature_importances_})
tmp = tmp.sort_values(by='Importância da feature',ascending=False)
plt.figure(figsize = (7,4))
plt.title('Importância da feature - Random Forest',fontsize=14)
s = sns.barplot(x='Feature',y='Importância da feature',data=tmp)
s.set_xticklabels(s.get_xticklabels(),rotation=90)
plt.show()
Figura 13: Gráfico que apresenta a importância de cada feature para o modelo de Random Forest construído.
A partir da análise do gráfico de barras acima, vemos o grupo a qual o curso do estudante pertence é o fator que mais impacta na sua classificão com base na nota final. Notamos também que o Instituição, o município em que o curso é oferecido e a Renda familiar do estudante também influencia diretamente no resultado. O grau de escolaridade dos pais também é um fator que pode determinar o desempenho do estudante.
Podemos concluir a partir da análise da importância das features para o modelo e de todas as análises feitas anteriormente que está relacionado com sua situação socioconômica, a instituição em realiza o curso, a região em que vive, as oportunidades que teve durante o a graduação e nível de escoloridade de seus familiares. Vemos então que há uma necessidade de investimento na educação principalmente de minorias pertencentes à famílias menos favorecidas e em estados no Norte e Nordeste.
Na tabela baixo se encontram as ferramentas utilizadas na elaboraçào desse trabalho e um endereço eletrônico de referência de onde podem ser encontradas.
Ferramenta | Versão | Motivo Escolha |
---|---|---|
Jupyter Notebook | 6.3.0 | Foi a ferramenta escolhida para implementação pois oferece a opção de desenvolvimentos de notebooks e acesso de arquivos locais. |
Python | 3.8.8 | Foi a linguagem escolhida por exigir menos do computador e pelo fato da estudantes ter maior domínio com modelagem e visualização de dados com a linguagem ja que lida com isso no estágio. |
SQlite | 3.36.0 | Foi escolhida por ser um sistema que possui um gerenciamento mais simples através do python. |
SQliteStudio | 3.3.3 | Foi escolhida por ser uma interface de fácil de manipulação de um banco de dados em Sqlite. |
Git bash | 2.33.0 | Foi escolhida pois fornece um jeito rápido e eficiente de maniputar repositórios no Github. |
Visual Paradigm | 16.3 | Foi escolhida pois foi uma ferramenta bastante utilizada pelo professor durante o curso. |
1 - Repositório no Github contendo o trabalho. Disponível em:
\< https://github.com/leticiatavaresds/DW_ENADE> Último Acesso em: 29 de nov. de 2021.
2 - Microdados do Exame Nacional de Desempenho dos Estudantes. Disponível em:
\<https://www.gov.br/inep/pt-br/acesso-a-informacao/dados-abertos/microdados/enade> Último Acesso em: 29 de nov. de 2021.
3 - Dados Conceito Exame Nacional de Desempenho dos Estudantes. Disponível em:
\<https://www.gov.br/inep/pt-br/areas-de-atuacao/pesquisas-estatisticas-e-indicadores/indicadores-de-qualidade-da-educacao-superior/outros-documentos> Último Acesso em: 29 de nov. de 2021.
4 - Diagrama em png do modelo dimensional estrala elaborado. Disponível em:
\<https://raw.githubusercontent.com/leticiatavaresds/DW_ENADE/main/Modelo%20Dimensional%20Estrela/ENADE.png> Último Acesso em: 29 de nov. de 2021.
5 - sklearn.ensemble.RandomForestClassifier Documentação. Disponível em:
\<https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html> Último Acesso em: 29 de nov. de 2021.
6 - Improve your classification models using Mean /Target Encoding. Disponível em:
\<https://medium.datadriveninvestor.com/improve-your-classification-models-using-mean-target-encoding-a3d573df31e8> Último Acesso em: 29 de nov. de 2021.
7 - Um guia completo para modelagem dimensional. Disponível em:
\<https://www.astera.com/pt/tipo/blog/guia-de-modelagem-dimensional/> Último Acesso em: 29 de nov. de 2021.
8 - Slite3 Documentação. Disponível em:
\< https://docs.python.org/3/library/sqlite3.html> Último Acesso em: 29 de nov. de 2021.