Letícia Tavares
Menu

Letícia Tavares

Analista de Dados Cientista de Dados

Descrição

Análise ENADE 2017, 2018 e 2019

Enade

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.

Sumário

Introduçã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].

Microdados ENADE

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.

Obtenção dos Dados

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

  • Importação de Bibliotecas

In [1]:
# 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
      
  • Variáveis Globais

In [2]:
diretorio_atual = os.path.dirname(os.path.realpath('__file__')) + "\\"
      diretorio_dados = diretorio_atual + "Dados\\"
      
  • Função para download de um arquivo


In [3]:
#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")
      
  • Download Microdados ENADE

In [4]:
# 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)
      
      Arquivo microdados_enade_2017.zip salvo com sucesso.         

      Arquivo microdados_enade_2018.zip salvo com sucesso.         

      Arquivo microdados_enade_2019.zip salvo com sucesso.         
      
  • Download Conceito ENADE

In [5]:
# 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)
      
      Arquivo conceito_enade_2017.xlsx salvo com sucesso.         

      Arquivo conceito_enade_2018.xlsx salvo com sucesso.         

      Arquivo conceito_enade_2019.xlsx salvo com sucesso.         
      

Modelagem de Dados

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.

Tratamento de Dados

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.

Importação de Bibliotecas

In [6]:
# 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
      

Variáveis Globais

In [7]:
# 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()
      

Leitura de Dados

Leitura Microdados Enade

In [8]:
# 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")     
      
In [9]:
leitura_microdados()
      
Microdados do ano 2017 importados com sucesso para a variável df_enade_2017

      Microdados do ano 2018 importados com sucesso para a variável df_enade_2018.

      Microdados do ano 2019 importados com sucesso para a variável df_enade_2019.

      

Leitura Códigos Cidades Microdados ENADE

In [10]:
# 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")     
      
In [11]:
leitura_cod_cidades()
      
Dados dos Códigos das Cidades importados com sucesso para a variável df_cod_cidades.

      

Leitura Dados Conceito ENADE

In [12]:
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")  
      
In [13]:
leitura_conceito_ENADE()
      
Conceito do ENADE do ano 2017 importado com sucesso para a variável df_con_2017

      Conceito do ENADE do ano 2018 importado com sucesso para a variável df_con_2018

      Conceito do ENADE do ano 2019 importado com sucesso para a variável df_con_2019

      

Leitura dicionário

In [14]:
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")     
      
In [15]:
leitura_dicionarios()
      
Dicionário dos Microdados importados com sucesso para a variável df_dicionario.

      

Tratamento de Dados

Eliminação de Colunas que se encontram apenas na base de 2017

In [16]:
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)
      

Concatenação das Bases de 2017, 2018 e 2019

In [17]:
df_enade_17_18_19 = pd.concat([df_enade_2017, df_enade_2018, df_enade_2019]).reset_index(drop = True)
      
In [18]:
df_enade_17_18_19.shape
      
Out[18]:
(1519493, 137)
In [19]:
df_con_17_18_19 = pd.concat([df_con_2017, df_con_2018, df_con_2019]).reset_index(drop = True)
      
In [20]:
# df_enade_17_18_19.sample(4)
      

Eliminacao amostras vazias ou com nan na coluna de Nota Geral

In [21]:
df_enade_17_18_19 = df_enade_17_18_19.replace(' ', np.nan)
      
In [22]:
# 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) 
      
In [23]:
df_enade_17_18_19.shape
      
Out[23]:
(1302299, 137)

Eliminação de NaN em outras colunas utilizadas

In [24]:
turno_maisf_ies = df_enade_17_18_19.groupby(['CO_IES'])["CO_TURNO_GRADUACAO"].agg(pd.Series.mode).to_frame()
      
In [25]:
dicionario_turno_ies = dict(zip(turno_maisf_ies.index, turno_maisf_ies['CO_TURNO_GRADUACAO']))
      
In [26]:
index_nan = df_enade_17_18_19[df_enade_17_18_19["CO_TURNO_GRADUACAO"].isna()].index.to_list()
      
In [167]:
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
      
In [28]:
df_enade_17_18_19.CO_TURNO_GRADUACAO.value_counts(dropna = False)
      
Out[28]:
4.0    686757
      3.0    424100
      1.0    155197
      2.0     35953
      NaN       292
      Name: CO_TURNO_GRADUACAO, dtype: int64
In [29]:
# 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
      
In [30]:
df_enade_17_18_19 = df_enade_17_18_19.dropna(subset=["QE_I01"]).reset_index(drop = True) # 10231 nulos
      
In [31]:
df_enade_17_18_19.shape
      
Out[31]:
(1291776, 137)

Eliminação de amostras duvidosas

In [32]:
#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]
      

Renomeação de Colunas

In [33]:
df_enade_17_18_19 = df_enade_17_18_19.rename(columns = {"NU_ANO": "ID_TEMPO"})
      

Modelo Estrela do ENADE

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:

Diagram Description automatically generated

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

  1. Das 169 variáveis restantes, foram selecionadas as que mais pareciam estar relacionadas à nota do estudante como dados da instituição de ensino do curso, dados econômicos do estudante, percepção da prova, entre outros. A seguir se encontra uma breve descrição de cada tabela presente no modelo elaborado e das variáveis que cada uma possui.
  • DIM_ALUNO_ECON: possui variáveis importantes associadas à indicadores econômicos do estudante.
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.
  • DIM_TEMPO: possui uma variável que descreve o tempo na granularidade de ano.
ID_TEMPO Numérico Chave Primária
ANO Numérico Ano da prova. A coluna foi renomeada, o nome original é NU_ANO.
  • DIM_IES: possui variáveis referentes à Instuição em que o estudando cursa a graduação. A tabela foi construída utilizando também os dados da base Conceito Enade.
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.
  • DIM_ENSINO_MEDIO: possui variáveis referentes ao ensino médio cursado pelo estudante. As varáveis fazem parte do questionário do estudante e os valores foram substitídos pelos significados apresentados 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.
  • DIM_FORMACAO_FAMILIARES: possui variáveis associadas à escolarização de familiares do estudante. As varáveis fazem parte do questionário do estudante e os valores foram substitídos pelos significados apresentados 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.
  • DIM_CURSO: possui variáveis referentes curso em que o estudante está graduando.
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.
  • DIM_REGIAO: possui variáveis associadas à região a qual a Instiuição em que o aluno presta o curso pertence em várias granularidades de divisões territoriais. Foi construída a partir do dicionário dos Microdados.
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.
  • DIM_PERCEPCAO_PROVA: possui variáveis associadas à percepções que o aluno teve após concluir a prova. As varáveis fazem parte do questionário de percepção da prova e os valores foram substitídos pelos significados apresentados 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.
  • DIM_PRESENCA: possui variáveis associadas à presença do aluno nas seções da Prova que indicam se aluno teve uma participação válida ou zerada por algum motivo como ausência ou anulação.
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.
  • DIM_OPORTUNIDADES possui variáveis associadas à opinião do estudante sobre oportunidades durante a graduação. As varáveis fazem parte do questionário do estudante e os valores foram substitídos pelos significados apresentados no dicionário.
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.
  • DIM_INFO_ALUNO: possui variáveis importantes associadas à indicadores sociais do aluno.
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.
  • FATO_PROVA: Tabela fato do modelo que apresenta as notas da prova obtidas pelo estutande.:
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.

Banco de Dados

Alimentação do Banco de Dados

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

Criação das Tabelas de Dimensão e Fato

Dimensão Tempo

In [34]:
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()
      
In [35]:
dim_tempo.head(3)
      
Out[35]:
ANO
ID_TEMPO
2017 2017
2018 2018
2019 2019

Dimensão Curso

In [36]:
df_enade_17_18_19["ID_CURSO"] = df_enade_17_18_19.groupby(['CO_MODALIDADE','CO_GRUPO']).ngroup()
      
In [37]:
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()
      
In [38]:
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})
      
In [39]:
dim_curso = dim_curso.rename(columns = {"CO_MODALIDADE" : "MODALIDADE_CURSO",
                            "CO_GRUPO" : "GRUPO_CURSO"})
      
In [40]:
dim_curso.head(3)
      
Out[40]:
MODALIDADE_CURSO GRUPO_CURSO
ID_CURSO
0 Educação a Distância ENFERMAGEM
1 Educação a Distância NUTRIÇÃO
2 Educação a Distância BIOMEDICINA

Dimensão IES

In [41]:
df_enade_17_18_19["ID_IES_ANO"] = df_enade_17_18_19.groupby(['CO_IES', 'CO_CATEGAD',  'CO_ORGACAD']).ngroup()
      
In [42]:
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()
      
In [43]:
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})
      
In [44]:
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})
      
In [45]:
dim_ies = dim_ies.rename(columns = {"CO_IES" : "NOME_IES",
                                            "CO_CATEGAD" : "CATEGORIA_IES",
                                            "CO_ORGACAD" : "ORGANIZACAO_IES"})
      
In [46]:
dim_ies.head(4)
      
Out[46]:
NOME_IES CATEGORIA_IES ORGANIZACAO_IES
ID_IES_ANO
0 UNIVERSIDADE FEDERAL DE MATO GROSSO Pública Federal Universidade
1 UNIVERSIDADE FEDERAL DE MATO GROSSO Pública Federal Universidade
2 UNIVERSIDADE DE BRASÍLIA Pública Federal Universidade
3 UNIVERSIDADE DE BRASÍLIA Pública Federal Universidade

Dimensão Região

In [47]:
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)
      
In [48]:
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"})
      
In [49]:
df_cod_cidades = df_cod_cidades.rename(columns = {"CÓDIGO DO MUNICÍPIO": "CO_MUNIC_CURSO",
                                                        "NOME DO MUNICÍPIO": "NOME_MUNICIPIO"})
      
In [50]:
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)
      
Out[50]:
NOME_MUNICIPIO UF REGIAO_CURSO
CO_MUNIC_CURSO
1100023 ARIQUEMES RO Norte
1100049 CACOAL RO Norte
1100064 COLORADO DO OESTE RO Norte

Dimensão Presença

In [51]:
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()
      
In [52]:
dicionario_presenca_prova = { 333 : 0,
                                    555 : 1}
      
In [53]:
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)
      
In [54]:
dim_presenca.head()
      
Out[54]:
TP_PR_OB_FG TP_PR_DI_FG TP_PR_OB_CE TP_PR_DI_CE
ID_PRESENCA
0 0 0 0 0
1 0 0 0 1
2 0 0 1 0
3 0 0 1 1
4 0 1 0 0

Dimensão Aluno Socio

In [55]:
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)
      
In [56]:
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()
      
In [57]:
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()
      
In [58]:
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})
      
In [59]:
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)
      
In [60]:
dim_info_aluno.head()
      
Out[60]:
NU_IDADE TP_SEXO CO_TURNO_GRADUACAO ESTADO_CIVIL RAÇA NACIONALIDADE
ID_ALUNO_INFO
0 16 M 4 Solteiro(a) Branca Brasileira
1 17 F 2 Solteiro(a) Branca Brasileira
2 17 M 3 Solteiro(a) Parda Brasileira
3 18 F 1 Solteiro(a) Branca Brasileira
4 18 F 1 Solteiro(a) Parda Brasileira

Dimensao Ensino Médio

In [61]:
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)
      
In [62]:
df_enade_17_18_19["ID_ALUNO_ENSINO_MEDIO"] = df_enade_17_18_19.groupby(['QE_I17','QE_I18']).ngroup()
      
In [63]:
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()
      
In [64]:
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})
      
In [65]:
dim_ensino_medio = dim_ensino_medio.rename(columns = {"QE_I17" : "TIPO_ESCOLA_EM",
                            "QE_I18" : "MODALIDADE_EM"})
      
In [66]:
dim_ensino_medio.head(3)
      
Out[66]:
TIPO_ESCOLA_EM MODALIDADE_EM
ID_ALUNO_ENSINO_MEDIO
0 Todo em escola pública Ensino médio tradicional
1 Todo em escola pública Profissionalizante técnico
2 Todo em escola pública Profissionalizante magistério

Dimensao Formação Familiares

In [67]:
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)
      
In [68]:
df_enade_17_18_19["ID_FORMACAO_FAMILIA"] = df_enade_17_18_19.groupby(['QE_I04','QE_I05','QE_I21']).ngroup()
      
In [69]:
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()
      
In [70]:
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})
      
In [71]:
dim_formacao_familiares = dim_formacao_familiares.rename(columns = {"QE_I04" : "ESCOLARIZACAO_PAI",
                            "QE_I05" : "ESCOLARIZACAO_MAE",
                            "QE_I21" : "FAMILIAR_GRADUADO"})
      
In [72]:
dim_formacao_familiares.head(5)
      
Out[72]:
ESCOLARIZACAO_PAI ESCOLARIZACAO_MAE FAMILIAR_GRADUADO
ID_FORMACAO_FAMILIA
0 Nenhuma Nenhuma Sim
1 Nenhuma Nenhuma Não
2 Nenhuma Ensino Fundamental: 1º ao 5º ano (1ª a 4ª série) Sim
3 Nenhuma Ensino Fundamental: 1º ao 5º ano (1ª a 4ª série) Não
4 Nenhuma Ensino Fundamental: 6º ao 9º ano (5ª a 8ª série) Sim

Dimensao Oportunidades

In [73]:
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)
      
In [74]:
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()
      
In [75]:
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()
      
In [76]:
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})
      
In [77]:
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"})
      
In [78]:
dim_oportunidades.head(4)
      
Out[78]:
ATIVIDADES_CURRICURALES_EXTERIOR IDIOMA_ESTRANGEIRO EXTENSAO_UNIVERSITARIA ATIVIDADES_INVESTIGACAO_ACADEMICA INTERCAMBIO_ESTAGIO_PAIS INTERCAMBIO_ESTAGIO_FORA_DO_PAIS
ID_OPORTUNIDADES
0 Não participei Modalidade presencial Discordo Totalmente Discordo Totalmente Discordo Totalmente Discordo Totalmente
1 Não participei Modalidade presencial Discordo Totalmente Discordo Totalmente Discordo Totalmente Discordo Parcialmente
2 Não participei Modalidade presencial Discordo Totalmente Discordo Totalmente Discordo Totalmente Nem Discordo Nem Concordo
3 Não participei Modalidade presencial Discordo Totalmente Discordo Totalmente Discordo Totalmente Concordo Um Pouco

Dimensao Aluno Economico

In [79]:
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)
      
In [80]:
dim_aluno_econ = df_enade_17_18_19[['QE_I07','QE_I08','QE_I10','QE_I12','QE_I15']].copy()
      
In [81]:
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})
      
In [82]:
df_enade_17_18_19.QE_I07.value_counts(dropna = False)
      
Out[82]:
D    318079
      C    301603
      B    208137
      E    177639
      A    165505
      F     74013
      G     27492
      H     19303
      Name: QE_I07, dtype: int64
In [83]:
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()
      
In [84]:
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"})
      
In [85]:
dim_aluno_econ.head(3)
      
Out[85]:
PESSOAS_MORAM_JUNTO RENDA_FAMILIAR HORAS_TRABALHO AUXILIO_RECEBIDO ENTROU_POR_COTA
ID_ALUNO_ECONOMICO
0 Cinco Acima de 30 salários mínimos Não estou trabalhando. Auxílio alimentação Não
1 Cinco Acima de 30 salários mínimos Não estou trabalhando. Auxílio moradia e alimentação Não
2 Cinco Acima de 30 salários mínimos Não estou trabalhando. Nenhum Combinação de dois ou mais critérios

Dimensao Percepcao Prova

In [86]:
dim_percepcao_prova = df_enade_17_18_19[['CO_RS_I1','CO_RS_I2','CO_RS_I8','CO_RS_I9']].copy()
      
In [87]:
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})
      
In [88]:
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()
      
In [89]:
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"})
      
In [90]:
dim_percepcao_prova.head(4)
      
Out[90]:
GRAU_DIFICULDADE_FG GRAU_DIFICULDADE_CE PERCEPCAO_ESTUDO_CONTEUDO TEMPO_GASTO_PROVA
ID_PERCEPCAO_PROVA
0 Difícil Difícil Estudou a maioria, mas nao aprendeu 0.5
1 Difícil Difícil Estudou a maioria, mas nao aprendeu 1.5
2 Difícil Difícil Estudou a maioria, mas nao aprendeu 2.5
3 Difícil Difícil Estudou a maioria, mas nao aprendeu 3.5

Tabela Fato

In [91]:
colunas_ID = [col for col in df_enade_17_18_19 if col.startswith('ID_') or col.startswith('CO_MUNIC')]
      
In [92]:
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"
      
In [93]:
# fato_prova.head(4)
      

Inserção de Tabelas na Base de Dados

In [94]:
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
      
In [95]:
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
      
In [96]:
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)
      
In [97]:
# 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")
      
Conexão ao banco 'Enade_DW.sqlite' criada com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_ALUNO_ECON criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_ALUNO_ECON com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_CURSO criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_CURSO com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_ENSINO_MEDIO criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_ENSINO_MEDIO com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_FORMACAO_FAMILIARES criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_FORMACAO_FAMILIARES com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_IES criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_IES com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_INFO_ALUNO criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_INFO_ALUNO com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_OPORTUNIDADES criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_OPORTUNIDADES com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_PERCEPCAO_PROVA criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_PERCEPCAO_PROVA com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_PRESENCA criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_PRESENCA com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_REGIAO criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_REGIAO com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela DIM_TEMPO criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela DIM_TEMPO com sucesso.

      ------------------------------------------------------------------------------------------
      Tabela FATO_PROVA criada com sucesso no banco Enade_DW.sqlite.

      Microdados importados para a tabela FATO_PROVA com sucesso.

      ------------------------------------------------------------------------------------------
      Conexão ao banco 'Enade_DW.sqlite' encerrada com sucesso.

      

Análise Exploratória

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.

Importação de Bibliotecas

In [98]:
# 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)
      

Variáveis Globais

In [99]:
# 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"
      

Importação Tabelas do Banco de Dados

In [100]:
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
      
In [101]:
# 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")
      
Conexão ao banco 'Enade_DW.sqlite' criada com sucesso.

      ------------------------------------------------------------------------------------------
      Tabelas importadas com Sucesso.DadosEnade_DW.sqlite...
                          
      ------------------------------------------------------------------------------------------
      Conexão ao banco 'Enade_DW.sqlite' encerrada com sucesso.

      

Análise de Dados

In [102]:
df_aluno_info = dim_info_aluno.join(fato_prova.set_index("ID_ALUNO_INFO")[['NT_GER', 
                                                                                'NT_FG','NT_CE']])
      
In [103]:
df_aluno_info["NT_GER_INTEIRO"] = df_aluno_info["NT_GER"].astype(int)
      

Nota por Gênero

In [104]:
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")
      
In [105]:
rp.summary_cont(df_aluno_info['NT_GER'].groupby(df_aluno_info['TP_SEXO']))
      

      
Out[105]:
N Mean SD SE 95% Conf. Interval
TP_SEXO
Feminino 739651 42.864 14.170 0.017 42.832 42.897
Masculino 552120 43.469 14.596 0.020 43.431 43.508

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.

In [106]:
ordem_valores = {"TP_SEXO" : ['Feminino', 'Masculino']}
      labels = {"TP_SEXO" : "GÊNERO",
              "NT_GER_INTEIRO" : "NOTA_GERAL"}
      
In [107]:
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.

In [108]:
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.

Nota por Raça

In [109]:
rp.summary_cont(df_aluno_info['NT_GER'].groupby(df_aluno_info['RAÇA']))
      

      
Out[109]:
N Mean SD SE 95% Conf. Interval
RAÇA
Amarela 31191 41.947 14.073 0.080 41.791 42.103
Branca 688299 44.479 14.446 0.017 44.445 44.514
Indígena 4408 39.305 13.966 0.210 38.893 39.718
Não quero declarar 27901 45.882 15.257 0.091 45.703 46.061
Parda 425617 41.307 14.010 0.021 41.265 41.350
Preta 114355 41.508 13.955 0.041 41.427 41.589

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.

In [110]:
ordem_valores = {"RAÇA" : ['Amarela', 'Branca','Indígena','Parda','Preta','Não quero declarar']}
      cores = ['#19D3F3', '#FFA15A', '#AB63FA',  '#00CC96', '#EF553B', '#636EFA']
      
In [111]:
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()
      
In [112]:
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.

Nota por Idade

In [113]:
df_aluno_info[["NU_IDADE"]].describe()
      
Out[113]:
NU_IDADE
count 1291771.000
mean 28.462
std 7.657
min 16.000
25% 23.000
50% 26.000
75% 32.000
max 87.000

>

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.

In [114]:
df_aluno_info['MEDIA_NOTA_GERAL'] = df_aluno_info.groupby(['NU_IDADE'])['NT_GER'].transform('mean')
      
In [115]:
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()
      
In [116]:
df_aluno_info[["NU_IDADE", "NT_GER"]].corr()
      
Out[116]:
NU_IDADE NT_GER
NU_IDADE 1.000 -0.151
NT_GER -0.151 1.000

Tabela 4: Correlação entre a variável idade e a nota geral

Nota por Região

In [117]:
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)
      
In [118]:
rp.summary_cont(df_regiao_tempo['NT_GER'].groupby(df_regiao_tempo['UF']))
      

      
Out[118]:
N Mean SD SE 95% Conf. Interval
UF
AC 3868 40.181 13.360 0.215 39.760 40.602
AL 14968 40.570 14.365 0.117 40.340 40.800
AM 21593 38.519 13.355 0.091 38.341 38.697
AP 4402 39.847 13.097 0.197 39.460 40.234
BA 52239 42.470 14.323 0.063 42.347 42.593
CE 40256 44.612 14.419 0.072 44.471 44.753
DF 27554 45.124 15.363 0.092 44.943 45.305
ES 19406 47.348 14.273 0.102 47.147 47.548
GO 35845 41.882 14.063 0.074 41.737 42.028
MA 20678 40.678 13.656 0.095 40.492 40.864
MG 139056 45.076 14.449 0.039 45.000 45.152
MS 21282 40.773 14.067 0.096 40.584 40.962
MT 16372 40.489 13.791 0.108 40.278 40.700
PA 26991 41.724 13.780 0.084 41.559 41.888
PB 23765 43.985 14.107 0.091 43.805 44.164
PE 42934 42.965 14.521 0.070 42.828 43.103
PI 18269 41.990 14.186 0.105 41.785 42.196
PR 133966 42.605 14.465 0.040 42.527 42.682
RJ 118393 43.749 14.518 0.042 43.667 43.832
RN 19375 44.038 14.536 0.104 43.833 44.243
RO 7885 40.796 13.313 0.150 40.502 41.090
RR 2677 38.036 13.351 0.258 37.530 38.542
RS 70107 45.719 14.225 0.054 45.614 45.824
SC 67569 42.529 14.132 0.054 42.422 42.635
SE 12864 42.279 14.336 0.126 42.031 42.527
SP 318157 42.753 14.171 0.025 42.703 42.802
TO 11300 39.393 13.745 0.129 39.140 39.647

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.

In [119]:
rp.summary_cont(df_regiao_tempo['NT_GER'].groupby(df_regiao_tempo['REGIAO_CURSO']))
      

      
Out[119]:
N Mean SD SE 95% Conf. Interval
REGIAO_CURSO
Centro-Oeste 101053 42.307 14.500 0.046 42.217 42.396
Nordeste 245348 42.866 14.362 0.029 42.809 42.923
Norte 78716 40.111 13.608 0.049 40.016 40.206
Sudeste 595012 43.644 14.356 0.019 43.607 43.680
Sul 271642 43.390 14.387 0.028 43.336 43.444

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.

In [120]:
df_regiao_tempo["NT_GER_INTEIRO"] = df_regiao_tempo["NT_GER"].astype(int)
      
In [121]:
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')
      
In [124]:
UF_ordem_alfabetica = list(df_regiao_tempo.UF.sort_values().drop_duplicates())
      
In [125]:
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.

In [126]:
ordem_valores = {"UF" : UF_ordem_alfabetica}
      
In [127]:
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)
      
In [128]:
df_regiao_tempo.head(4)
      
Out[128]:
CO_MUNIC_CURSO NOME_MUNICIPIO UF REGIAO_CURSO NT_GER NT_FG NT_CE ANO NT_GER_INTEIRO Count MEDIA_NOTA_GERAL
0 1100023 ARIQUEMES RO Norte 16.400 35.500 10.000 2017 16 2370 40.365
1 1100023 ARIQUEMES RO Norte 54.800 73.000 48.700 2017 54 2370 40.365
2 1100023 ARIQUEMES RO Norte 23.500 37.000 19.000 2017 23 2370 40.365
3 1100023 ARIQUEMES RO Norte 34.300 46.400 30.200 2017 34 2370 40.365
In [129]:
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.

In [130]:
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()
      
In [131]:
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()
      

Nota por Renda Familiar

In [132]:
df_economico = dim_aluno_econ.join(fato_prova.set_index("ID_ALUNO_ECONOMICO")[['ID_TEMPO','NT_GER', 
                                                                                'NT_FG','NT_CE']])
      
In [133]:
# 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)
      
In [134]:
rp.summary_cont(df_economico['NT_GER'].groupby(df_economico['RENDA_FAMILIAR']))
      

      
Out[134]:
N Mean SD SE 95% Conf. Interval
RENDA_FAMILIAR
Até 1,5 salário mínimo 258862 39.906 13.807 0.027 39.853 39.959
De 1,5 a 3 salários mínimos 364140 41.404 13.753 0.023 41.359 41.449
De 3 a 4,5 salários mínimos 269942 43.074 13.992 0.027 43.021 43.127
De 4,5 a 6 salários mínimos 143022 44.627 14.245 0.038 44.553 44.700
De 6 a 10 salários mínimos 146657 46.688 14.580 0.038 46.613 46.763
De 10 a 30 salários mínimos 91318 49.725 14.797 0.049 49.629 49.821
Acima de 30 salários mínimos 17830 50.460 15.203 0.114 50.236 50.683

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.

In [135]:
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"}
      
In [136]:
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.

Modelo de Predição

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.

In [137]:
# 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
      
In [138]:
# 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"
      
In [139]:
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
      
In [140]:
#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()
      
In [141]:
# 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")
      
Conexão ao banco 'Enade_DW.sqlite' criada com sucesso.

      ------------------------------------------------------------------------------------------
      Tabelas importadas com Sucesso.DadosEnade_DW.sqlite...
                          
      ------------------------------------------------------------------------------------------
      Conexão ao banco 'Enade_DW.sqlite' encerrada com sucesso.

      
In [142]:
# 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)
      
In [143]:
# 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)
      
In [144]:
df_completo.shape
      
Out[144]:
(1291771, 42)
In [145]:
df_completo_backup = df_completo.copy()
      

Modelos

In [146]:
from sklearn.ensemble import RandomForestClassifier
      
In [147]:
df_completo = df_completo_backup.copy()
      

Tempo de Prova

In [148]:
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)
      

Horas de Trabalho

In [149]:
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)
      

Avaliacao CE

In [150]:
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)
      

Moram Junto

In [151]:
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)
      

Renda Familiar

In [152]:
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)
      

Renda Familiar Per Capita

In [153]:
df_completo["RENDA_PER_CAPITA"] = df_completo.RENDA_FAMILIAR/(df_completo.PESSOAS_MORAM_JUNTO +1)
      

Familiar Graduado

In [154]:
df_completo['FAMILIAR_GRADUADO'] = np.where(df_completo['FAMILIAR_GRADUADO'] == 'Sim', 1, 0)
      

Modalidade

In [155]:
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)
      

Naturalidade

In [156]:
df_completo['NACIONALIDADE'] = np.where(df_completo['NACIONALIDADE'] == 'Brasileira', 1, 0)

      df_completo.NACIONALIDADE = df_completo.NACIONALIDADE.astype(int)
      

Colunas Categóricas Restantes - Mean Encoding

In [157]:
# 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'])
      

NOTA MAIOR QUE A NOTA MÉDIA DO ANO

In [158]:
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']
      

Modelo - Random Forest

In [159]:
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()
      
In [160]:
y = dataset_modelo["MAIOR_QUE_NOTA_MEDIA_ANO"]
      dataset_modelo = dataset_modelo.drop("MAIOR_QUE_NOTA_MEDIA_ANO", 
                                          axis = 1)
      
In [161]:
#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}")
      
A Acurácia do modelo é de: 0.693585595070368
      A Precisão do modelo é de: 0.6963125503574306
      
In [162]:
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.

In [163]:
print(classification_report(y_teste, y_pred))
      
              precision    recall  f1-score   support

            False       0.69      0.73      0.71     66693
              True       0.70      0.65      0.67     62485

          accuracy                           0.69    129178
        macro avg       0.69      0.69      0.69    129178
      weighted avg       0.69      0.69      0.69    129178

      

Figura 11: Estatísticas da predição realizada pelo Modelo de Random Forest.

In [164]:
plt.rcParams["figure.figsize"] = (8,6)
      metrics.plot_roc_curve(rfc,  x_teste, y_teste) 
      
Out[164]:
<sklearn.metrics._plot.roc_curve.RocCurveDisplay at 0x18c9e81e250>

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.

In [165]:
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.

Conclusão

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.

Ferramentas Utlizadas

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.

Referências

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.

Outros Projetos

Confira alguns dos meus outros projetos

Contato

FALE COMIGO!