<gh_stars>0
# -*- coding: utf-8 -*-
"""processo_kroton.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1zETffHK0zvo-kREbYlYNkWvTJRy4wyAH
"""

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

"""#Carregamento e análise dos dados"""

dados = pd.read_csv('/content/case_Formatura.csv',sep=';')
dados = dados[:5000] # Limitação para processamento

dados['SEMESTRE_DIFF'] = dados['SEMESTRES_CURSADOS'] - dados['DURACAO_CURSO']  # Verificação dos semestres teoricos vs real
dados.loc[dados['SEMESTRE_DIFF'] < 0, 'SEMESTRE_DIFF'] = 0 # Considerando os semestres negativos como zero
dados.head(5)

dados.shape

dados.info()

dados.corr()

"""#Modificação dos dados nan para 0
Como NOTA_ENEM não entrou no modelo, então pude zerar os outros parâmetro
"""

dados.fillna(0, inplace=True)
dados.head(5)

"""#Formatando dados para treino e normalizando eles"""

# Seleção das colunas que apresentaram uma correlação maior com SEMESTRE_DIFF
X = dados[
    [
        'DURACAO_CURSO',
        'PERIODOS_TRANCADOS',
        'NOTA',
        'NRO_TOTAL_REPRO',
        'NRO_REPRO_NORMAL',
        'NRO_REPRO_ACO',
        'TURNO_CURSO',
        'COD_CURSO'
    ]
].values
print(X)

y = dados[ 'SEMESTRE_DIFF'].values

X = X/np.amax(X,axis=0)
print(X, len(X))

ymax=np.amax(y)
y = y/ymax
print(y, len (y))

"""#Criando as funções de ativação"""

def sigmoid(Soma):
    return 1/(1+np.exp(-Soma))

def relu(Soma):
    return np.maximum(0,Soma)

"""#Arquitetura da Rede
Ela é composta de uma camada de entrada com 8 entradas, mais quatro camadas ocultas e uma saida, essa arquitetura tem a ideia de expandir as entradas e fazer a redução para uma unica saida
"""

arquitetura = [
    {"dim_entrada": 8, "dim_saida": 100, "ativacao": "relu"},
    {"dim_entrada": 100, "dim_saida": 1000, "ativacao": "relu"},
    {"dim_entrada": 1000, "dim_saida": 100, "ativacao": "relu"},    
    {"dim_entrada": 100, "dim_saida": 200, "ativacao": "relu"},
    {"dim_entrada": 200, "dim_saida": 1, "ativacao": "sigmoid"}    
]

"""#Funções para iniciar as camadas e veriicar ativação, podem retornar o custo ou não
O seed é para manter o teste controlado, para que não haja problemas com corte de dados diferentes
"""

def inicia_camadas(arquitetura, seed = 99):
    # inicia os valores aleatórios
    np.random.seed(seed)
    # numero de camadas da rede neural
    numero_de_camadas = len(arquitetura)
    # inicia armazenamento de parametros
    valores_parametros = {}
    
    # itera nas camadas da rede
    for indice, camada in enumerate(arquitetura):
        
        indice_camada = indice + 1
        
        # extrai o numero de nodos nas camadas
        tamanho_camada_entrada = camada["dim_entrada"]
        tamanho_camada_saida = camada["dim_saida"]
        
        # inicia os valores na matriz de pesos P
        # e o vetor de viés ou bias b
        valores_parametros['P' + str(indice_camada)] = np.random.randn(
            tamanho_camada_saida, tamanho_camada_entrada)  * 0.1
        valores_parametros['b' + str(indice_camada)] = np.random.randn(
            tamanho_camada_saida, 1) * 0.1
        
    return valores_parametros

def propaga_uma_camada(Ativado_anterior, Pesos_atual, b_atual, ativacao="relu"):
    # cálculo da entrada para a função de ativação
    Saida_atual = np.dot(Pesos_atual, Ativado_anterior) + b_atual
    
    # selecção da função de ativação
    if ativacao is "relu":
        func_ativacao = relu
    elif ativacao is "sigmoid":
        func_ativacao = sigmoid
    else:
        raise Exception('Ainda não implementamos essa funcao')
        
    # retorna a ativação calculada Ativado_atual e a matriz intermediária Saida
    return func_ativacao(Saida_atual), Saida_atual

def propaga_total(X, valores_parametros, arquitetura):
    # memoria temporaria para a retropropagacao
    memoria = {}
    # O vetor X é a ativação para a camada 0 
    Ativado_atual = X
    
    # iterações para as camadas
    for indice, camada in enumerate(arquitetura):
        # a numeração das camadas começa de 1
        indice_camada = indice + 1
        # utiliza a ativação da iteração anterior
        Ativado_anterior = Ativado_atual
        
        # extrai a função de ativação para a camada atual
        func_ativacao_atual = camada["ativacao"]
        # extrai os pesos da camada atual
        Pesos_atual = valores_parametros["P" + str(indice_camada)]
        # extrai o bias para a camada atual
        b_atual = valores_parametros["b" + str(indice_camada)]
        # cálculo da ativação para a camada atual
        Ativado_atual, Saida_atual = propaga_uma_camada(Ativado_anterior, Pesos_atual, b_atual, func_ativacao_atual)
        
        # salca os valores calculados na memória
        memoria["A" + str(indice)] = Ativado_anterior
        memoria["Z" + str(indice_camada)] = Saida_atual
       
    # retorna o vetor predito e um dicionário contendo os valores intermediários
    return Ativado_atual, memoria

valores_parametros = inicia_camadas(arquitetura, seed = 99)
y_estimado, memoria = propaga_total(np.transpose(X), valores_parametros, arquitetura)

y_estimado[0,0]*ymax

y[0]*ymax

"""#Retropropagação para melhoria da rede"""

def atualiza(valores_parametros, gradidentes, arquitetura, taxa_aprendizagem):

    # iterações pelas camadas
    for indice_camada, camada in enumerate(arquitetura, 1):
        valores_parametros["P" + str(indice_camada)] -= taxa_aprendizagem * gradidentes["dP" + str(indice_camada)]        
        valores_parametros["b" + str(indice_camada)] -= taxa_aprendizagem * gradidentes["db" + str(indice_camada)]

    return valores_parametros;

def valor_de_custo(Y_predito, Y):
    # numero_de_exemplos
    m = Y_predito.shape[1]
    
    custo = -1 / m * (np.dot(Y, np.log(Y_predito).T) + np.dot(1 - Y, np.log(1 - Y_predito).T))
    return np.squeeze(custo)

def retropropagacao_total(Y_predito, Y, memoria, valores_parametros, arquitetura):
   
    gradientes = {}
    
    # numero de exemplos
    #m = Y.shape[1]
    # para garantir que os dois vetores tenham a mesma dimensão
    Y = Y.reshape(Y_predito.shape)
    
    # inicia o algoritmo de gradiente descendente
    dAtivado_anterior = - (np.divide(Y, Y_predito) - np.divide(1 - Y, 1 - Y_predito));
    
    for indice_camada_anterior, camada in reversed(list(enumerate(arquitetura))):
        
        indice_camada_atual = indice_camada_anterior + 1
        # Função de ativação para a camada atual
        
        funcao_ativao_atual = camada["ativacao"]
        
        dAtivado_atual = dAtivado_anterior
        
        Ativado_anterior = memoria["A" + str(indice_camada_anterior)]
        Saida_atual = memoria["Z" + str(indice_camada_atual)]
        
        Pesos_atual = valores_parametros["P" + str(indice_camada_atual)]
        b_atual = valores_parametros["b" + str(indice_camada_atual)]
        
        dAtivado_anterior, dPesos_atual, db_atual = retropropagacao_uma_camada(
            dAtivado_atual, Pesos_atual, b_atual, Saida_atual, Ativado_anterior, funcao_ativao_atual)
        
        gradientes["dP" + str(indice_camada_atual)] = dPesos_atual
        gradientes["db" + str(indice_camada_atual)] = db_atual
    
    return gradientes

def sigmoid_retro(dAtivado, Saida):
    sig = sigmoid(Saida)
    return dAtivado * sig * (1 - sig)

def relu_retro(dAtivado, Saida):
    dSaida = np.array(dAtivado, copy = True)
    dSaida[Saida <= 0] = 0;
    return dSaida;

def retropropagacao_uma_camada(dAtivado_atual, Pesos_atual, b_atual, Saida_atual, Ativado_anterior, ativacao="relu"):
    # número de exemplos
    m = Ativado_anterior.shape[1]
    
    # seleção função de ativação
    if ativacao is "relu":
        func_ativacao_retro = relu_retro
    elif ativacao is "sigmoid":
        func_ativacao_retro = sigmoid_retro
    else:
        raise Exception('Ainda não implementamos essa funcao')
    
    # derivada da função de ativação
    dSaida_atual = func_ativacao_retro(dAtivado_atual, Saida_atual)
    
    # derivada da matriz de Pesos
    dPesos_atual = np.dot(dSaida_atual, Ativado_anterior.T) / m
    # derivada do vetor b
    db_atual = np.sum(dSaida_atual, axis=1, keepdims=True) / m
    # derivada da matriz A_anterior
    dAtivado_anterior = np.dot(Pesos_atual.T, dSaida_atual)

    return dAtivado_anterior, dPesos_atual, db_atual

"""#Função para definir o treino"""

def treino(X, Y,X_teste,Y_teste, arquitetura, epocas, taxa_aprendizagem):
    # Inicia os parâmetros da rede neural
    valores_parametros = inicia_camadas(arquitetura, 2)
    # Listas que vão guardar o progresso da aprendizagem da rede 
    historia_custo = []
    historia_custo_teste = []
   
    
    # Atualiza a cada época
    for i in range(epocas):
        # Propaga a rede - Foward propagation
        Y_predito, memoria = propaga_total(X, valores_parametros, arquitetura)
        
        Y_predito_teste, memoria2 = propaga_total(X_teste, valores_parametros, 
                                                  arquitetura)
        
        # calcula as métricas e salva nas listas de história
        custo = valor_de_custo(Y_predito, Y)
        historia_custo.append(custo)
        custo_teste = valor_de_custo(Y_predito_teste, Y_teste)
        historia_custo_teste.append(custo_teste)
        
        
        # Retropropagação - Backpropagation
        gradientes = retropropagacao_total(Y_predito, Y, memoria, 
                                           valores_parametros, arquitetura)
        # Atualiza os pesos
        valores_parametros = atualiza(valores_parametros, gradientes, 
                                      arquitetura, taxa_aprendizagem)
        
        if(i % 100 == 0):
            
            print("Iteração: {:05} - custo: {:.5f} ".format(i, custo))
            
            
    return valores_parametros, historia_custo, historia_custo_teste

"""#Split dos dados para treino e teste"""

X_treino, X_teste, y_treino, y_teste = train_test_split( X, y, test_size=0.43, random_state=42)

"""#Treino"""

# Treinamento
valores_parametros, historia_custo, historia_custo_teste = treino(np.transpose(X_treino), np.transpose(y_treino.reshape((y_treino.shape[0], 1))), 
                                                                  np.transpose(X_teste), np.transpose(y_teste.reshape((y_teste.shape[0], 1))), 
                                                                  arquitetura, 500, 0.01)

"""#Gráfico de treinamento"""

plt.plot(historia_custo,'g')
plt.plot(historia_custo_teste, 'r')
plt.legend(['Treinamento','Teste'])
plt.ylabel('Custo')
plt.xlabel('Épocas')
plt.show()

"""# Previsão"""

# Previsão
Y_pred, _ = propaga_total(np.transpose(X_teste), valores_parametros, arquitetura)

"""#Gráfico de previsão
É possivel notar que o modelo não respondeu bem para eventos extremos
"""

plt.plot(np.transpose(X_teste)[1],ymax*y_teste,'.r')
plt.plot(np.transpose(X_teste)[1],ymax*Y_pred.reshape([-1,1]),'.g')
plt.legend(['Reais','Preditos'])
plt.ylabel(['Reais','Preditos'])
plt.xlabel('group')
plt.show()

"""#Agregação dos resultados e ajustes"""

prev = []
real = []
for i in ymax*Y_pred.reshape([-1,1]):
    prev.append(i[0])
for i in ymax*y_teste:
    real.append(i)

df_test = pd.DataFrame({
    'real':real,
    'prev':prev
})
adjust_prev = df_test[df_test['real']==0]['prev'].mean()
adjust_prev

#Ajuste de valores zero, o modelo superestimou o valor de zero
df_test.loc[df_test['prev']<adjust_prev,'prev']=0.0
df_test = df_test.round(0)
df_test

accuracy_score(df_test['real'],df_test['prev'])

df_test.loc[df_test['real']>0,'real_binary']=1.0
df_test.loc[df_test['prev']>0,'prev_binary']=1.0
df_test.loc[df_test['real']<=0,'real_binary']=0.0
df_test.loc[df_test['prev']<=0,'prev_binary']=0.0
accuracy_score(df_test['real_binary'],df_test['prev_binary'])

print(f'A acurácia do modelo pra definir o numero de semestres foi de {round(accuracy_score(df_test["real"],df_test["prev"]),4)*100}%, para verificar se o aluno vai ou não se formar com atraso foi de {round(accuracy_score(df_test["real_binary"],df_test["prev_binary"]),4)*100}%.')
# -*- coding: utf-8 -*-
"""processo_kroton.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1zETffHK0zvo-kREbYlYNkWvTJRy4wyAH
"""

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

"""#Carregamento e análise dos dados"""

dados = pd.read_csv('/content/case_Formatura.csv',sep=';')
dados = dados[:5000] # Limitação para processamento

dados['SEMESTRE_DIFF'] = dados['SEMESTRES_CURSADOS'] - dados['DURACAO_CURSO']  # Verificação dos semestres teoricos vs real
dados.loc[dados['SEMESTRE_DIFF'] < 0, 'SEMESTRE_DIFF'] = 0 # Considerando os semestres negativos como zero
dados.head(5)

dados.shape

dados.info()

dados.corr()

"""#Modificação dos dados nan para 0
Como NOTA_ENEM não entrou no modelo, então pude zerar os outros parâmetro
"""

dados.fillna(0, inplace=True)
dados.head(5)

"""#Formatando dados para treino e normalizando eles"""

# Seleção das colunas que apresentaram uma correlação maior com SEMESTRE_DIFF
X = dados[
    [
        'DURACAO_CURSO',
        'PERIODOS_TRANCADOS',
        'NOTA',
        'NRO_TOTAL_REPRO',
        'NRO_REPRO_NORMAL',
        'NRO_REPRO_ACO',
        'TURNO_CURSO',
        'COD_CURSO'
    ]
].values
print(X)

y = dados[ 'SEMESTRE_DIFF'].values

X = X/np.amax(X,axis=0)
print(X, len(X))

ymax=np.amax(y)
y = y/ymax
print(y, len (y))

"""#Criando as funções de ativação"""

def sigmoid(Soma):
    return 1/(1+np.exp(-Soma))

def relu(Soma):
    return np.maximum(0,Soma)

"""#Arquitetura da Rede
Ela é composta de uma camada de entrada com 8 entradas, mais quatro camadas ocultas e uma saida, essa arquitetura tem a ideia de expandir as entradas e fazer a redução para uma unica saida
"""

arquitetura = [
    {"dim_entrada": 8, "dim_saida": 100, "ativacao": "relu"},
    {"dim_entrada": 100, "dim_saida": 1000, "ativacao": "relu"},
    {"dim_entrada": 1000, "dim_saida": 100, "ativacao": "relu"},    
    {"dim_entrada": 100, "dim_saida": 200, "ativacao": "relu"},
    {"dim_entrada": 200, "dim_saida": 1, "ativacao": "sigmoid"}    
]

"""#Funções para iniciar as camadas e veriicar ativação, podem retornar o custo ou não
O seed é para manter o teste controlado, para que não haja problemas com corte de dados diferentes
"""

def inicia_camadas(arquitetura, seed = 99):
    # inicia os valores aleatórios
    np.random.seed(seed)
    # numero de camadas da rede neural
    numero_de_camadas = len(arquitetura)
    # inicia armazenamento de parametros
    valores_parametros = {}
    
    # itera nas camadas da rede
    for indice, camada in enumerate(arquitetura):
        
        indice_camada = indice + 1
        
        # extrai o numero de nodos nas camadas
        tamanho_camada_entrada = camada["dim_entrada"]
        tamanho_camada_saida = camada["dim_saida"]
        
        # inicia os valores na matriz de pesos P
        # e o vetor de viés ou bias b
        valores_parametros['P' + str(indice_camada)] = np.random.randn(
            tamanho_camada_saida, tamanho_camada_entrada)  * 0.1
        valores_parametros['b' + str(indice_camada)] = np.random.randn(
            tamanho_camada_saida, 1) * 0.1
        
    return valores_parametros

def propaga_uma_camada(Ativado_anterior, Pesos_atual, b_atual, ativacao="relu"):
    # cálculo da entrada para a função de ativação
    Saida_atual = np.dot(Pesos_atual, Ativado_anterior) + b_atual
    
    # selecção da função de ativação
    if ativacao is "relu":
        func_ativacao = relu
    elif ativacao is "sigmoid":
        func_ativacao = sigmoid
    else:
        raise Exception('Ainda não implementamos essa funcao')
        
    # retorna a ativação calculada Ativado_atual e a matriz intermediária Saida
    return func_ativacao(Saida_atual), Saida_atual

def propaga_total(X, valores_parametros, arquitetura):
    # memoria temporaria para a retropropagacao
    memoria = {}
    # O vetor X é a ativação para a camada 0 
    Ativado_atual = X
    
    # iterações para as camadas
    for indice, camada in enumerate(arquitetura):
        # a numeração das camadas começa de 1
        indice_camada = indice + 1
        # utiliza a ativação da iteração anterior
        Ativado_anterior = Ativado_atual
        
        # extrai a função de ativação para a camada atual
        func_ativacao_atual = camada["ativacao"]
        # extrai os pesos da camada atual
        Pesos_atual = valores_parametros["P" + str(indice_camada)]
        # extrai o bias para a camada atual
        b_atual = valores_parametros["b" + str(indice_camada)]
        # cálculo da ativação para a camada atual
        Ativado_atual, Saida_atual = propaga_uma_camada(Ativado_anterior, Pesos_atual, b_atual, func_ativacao_atual)
        
        # salca os valores calculados na memória
        memoria["A" + str(indice)] = Ativado_anterior
        memoria["Z" + str(indice_camada)] = Saida_atual
       
    # retorna o vetor predito e um dicionário contendo os valores intermediários
    return Ativado_atual, memoria

valores_parametros = inicia_camadas(arquitetura, seed = 99)
y_estimado, memoria = propaga_total(np.transpose(X), valores_parametros, arquitetura)

y_estimado[0,0]*ymax

y[0]*ymax

"""#Retropropagação para melhoria da rede"""

def atualiza(valores_parametros, gradidentes, arquitetura, taxa_aprendizagem):

    # iterações pelas camadas
    for indice_camada, camada in enumerate(arquitetura, 1):
        valores_parametros["P" + str(indice_camada)] -= taxa_aprendizagem * gradidentes["dP" + str(indice_camada)]        
        valores_parametros["b" + str(indice_camada)] -= taxa_aprendizagem * gradidentes["db" + str(indice_camada)]

    return valores_parametros;

def valor_de_custo(Y_predito, Y):
    # numero_de_exemplos
    m = Y_predito.shape[1]
    
    custo = -1 / m * (np.dot(Y, np.log(Y_predito).T) + np.dot(1 - Y, np.log(1 - Y_predito).T))
    return np.squeeze(custo)

def retropropagacao_total(Y_predito, Y, memoria, valores_parametros, arquitetura):
   
    gradientes = {}
    
    # numero de exemplos
    #m = Y.shape[1]
    # para garantir que os dois vetores tenham a mesma dimensão
    Y = Y.reshape(Y_predito.shape)
    
    # inicia o algoritmo de gradiente descendente
    dAtivado_anterior = - (np.divide(Y, Y_predito) - np.divide(1 - Y, 1 - Y_predito));
    
    for indice_camada_anterior, camada in reversed(list(enumerate(arquitetura))):
        
        indice_camada_atual = indice_camada_anterior + 1
        # Função de ativação para a camada atual
        
        funcao_ativao_atual = camada["ativacao"]
        
        dAtivado_atual = dAtivado_anterior
        
        Ativado_anterior = memoria["A" + str(indice_camada_anterior)]
        Saida_atual = memoria["Z" + str(indice_camada_atual)]
        
        Pesos_atual = valores_parametros["P" + str(indice_camada_atual)]
        b_atual = valores_parametros["b" + str(indice_camada_atual)]
        
        dAtivado_anterior, dPesos_atual, db_atual = retropropagacao_uma_camada(
            dAtivado_atual, Pesos_atual, b_atual, Saida_atual, Ativado_anterior, funcao_ativao_atual)
        
        gradientes["dP" + str(indice_camada_atual)] = dPesos_atual
        gradientes["db" + str(indice_camada_atual)] = db_atual
    
    return gradientes

def sigmoid_retro(dAtivado, Saida):
    sig = sigmoid(Saida)
    return dAtivado * sig * (1 - sig)

def relu_retro(dAtivado, Saida):
    dSaida = np.array(dAtivado, copy = True)
    dSaida[Saida <= 0] = 0;
    return dSaida;

def retropropagacao_uma_camada(dAtivado_atual, Pesos_atual, b_atual, Saida_atual, Ativado_anterior, ativacao="relu"):
    # número de exemplos
    m = Ativado_anterior.shape[1]
    
    # seleção função de ativação
    if ativacao is "relu":
        func_ativacao_retro = relu_retro
    elif ativacao is "sigmoid":
        func_ativacao_retro = sigmoid_retro
    else:
        raise Exception('Ainda não implementamos essa funcao')
    
    # derivada da função de ativação
    dSaida_atual = func_ativacao_retro(dAtivado_atual, Saida_atual)
    
    # derivada da matriz de Pesos
    dPesos_atual = np.dot(dSaida_atual, Ativado_anterior.T) / m
    # derivada do vetor b
    db_atual = np.sum(dSaida_atual, axis=1, keepdims=True) / m
    # derivada da matriz A_anterior
    dAtivado_anterior = np.dot(Pesos_atual.T, dSaida_atual)

    return dAtivado_anterior, dPesos_atual, db_atual

"""#Função para definir o treino"""

def treino(X, Y,X_teste,Y_teste, arquitetura, epocas, taxa_aprendizagem):
    # Inicia os parâmetros da rede neural
    valores_parametros = inicia_camadas(arquitetura, 2)
    # Listas que vão guardar o progresso da aprendizagem da rede 
    historia_custo = []
    historia_custo_teste = []
   
    
    # Atualiza a cada época
    for i in range(epocas):
        # Propaga a rede - Foward propagation
        Y_predito, memoria = propaga_total(X, valores_parametros, arquitetura)
        
        Y_predito_teste, memoria2 = propaga_total(X_teste, valores_parametros, 
                                                  arquitetura)
        
        # calcula as métricas e salva nas listas de história
        custo = valor_de_custo(Y_predito, Y)
        historia_custo.append(custo)
        custo_teste = valor_de_custo(Y_predito_teste, Y_teste)
        historia_custo_teste.append(custo_teste)
        
        
        # Retropropagação - Backpropagation
        gradientes = retropropagacao_total(Y_predito, Y, memoria, 
                                           valores_parametros, arquitetura)
        # Atualiza os pesos
        valores_parametros = atualiza(valores_parametros, gradientes, 
                                      arquitetura, taxa_aprendizagem)
        
        if(i % 100 == 0):
            
            print("Iteração: {:05} - custo: {:.5f} ".format(i, custo))
            
            
    return valores_parametros, historia_custo, historia_custo_teste

"""#Split dos dados para treino e teste"""

X_treino, X_teste, y_treino, y_teste = train_test_split( X, y, test_size=0.43, random_state=42)

"""#Treino"""

# Treinamento
valores_parametros, historia_custo, historia_custo_teste = treino(np.transpose(X_treino), np.transpose(y_treino.reshape((y_treino.shape[0], 1))), 
                                                                  np.transpose(X_teste), np.transpose(y_teste.reshape((y_teste.shape[0], 1))), 
                                                                  arquitetura, 500, 0.01)

"""#Gráfico de treinamento"""

plt.plot(historia_custo,'g')
plt.plot(historia_custo_teste, 'r')
plt.legend(['Treinamento','Teste'])
plt.ylabel('Custo')
plt.xlabel('Épocas')
plt.show()

"""# Previsão"""

# Previsão
Y_pred, _ = propaga_total(np.transpose(X_teste), valores_parametros, arquitetura)

"""#Gráfico de previsão
É possivel notar que o modelo não respondeu bem para eventos extremos
"""

plt.plot(np.transpose(X_teste)[1],ymax*y_teste,'.r')
plt.plot(np.transpose(X_teste)[1],ymax*Y_pred.reshape([-1,1]),'.g')
plt.legend(['Reais','Preditos'])
plt.ylabel(['Reais','Preditos'])
plt.xlabel('group')
plt.show()

"""#Agregação dos resultados e ajustes"""

prev = []
real = []
for i in ymax*Y_pred.reshape([-1,1]):
    prev.append(i[0])
for i in ymax*y_teste:
    real.append(i)

df_test = pd.DataFrame({
    'real':real,
    'prev':prev
})
adjust_prev = df_test[df_test['real']==0]['prev'].mean()
adjust_prev

#Ajuste de valores zero, o modelo superestimou o valor de zero
df_test.loc[df_test['prev']<adjust_prev,'prev']=0.0
df_test = df_test.round(0)
df_test

accuracy_score(df_test['real'],df_test['prev'])

df_test.loc[df_test['real']>0,'real_binary']=1.0
df_test.loc[df_test['prev']>0,'prev_binary']=1.0
df_test.loc[df_test['real']<=0,'real_binary']=0.0
df_test.loc[df_test['prev']<=0,'prev_binary']=0.0
accuracy_score(df_test['real_binary'],df_test['prev_binary'])

print(f'A acurácia do modelo pra definir o numero de semestres foi de {round(accuracy_score(df_test["real"],df_test["prev"]),4)*100}%, para verificar se o aluno vai ou não se formar com atraso foi de {round(accuracy_score(df_test["real_binary"],df_test["prev_binary"]),4)*100}%.')
# -*- coding: utf-8 -*- processo_kroton.ipynb  Automatically generated by Colaboratory.  Original file is located at     https://colab.research.google.com/drive/1zETffHK0zvo-kREbYlYNkWvTJRy4wyAH #Carregamento e análise dos dados # Limitação para processamento # Verificação dos semestres teoricos vs real # Considerando os semestres negativos como zero #Modificação dos dados nan para 0 Como NOTA_ENEM não entrou no modelo, então pude zerar os outros parâmetro #Formatando dados para treino e normalizando eles # Seleção das colunas que apresentaram uma correlação maior com SEMESTRE_DIFF #Criando as funções de ativação #Arquitetura da Rede Ela é composta de uma camada de entrada com 8 entradas, mais quatro camadas ocultas e uma saida, essa arquitetura tem a ideia de expandir as entradas e fazer a redução para uma unica saida #Funções para iniciar as camadas e veriicar ativação, podem retornar o custo ou não O seed é para manter o teste controlado, para que não haja problemas com corte de dados diferentes # inicia os valores aleatórios # numero de camadas da rede neural # inicia armazenamento de parametros # itera nas camadas da rede # extrai o numero de nodos nas camadas # inicia os valores na matriz de pesos P # e o vetor de viés ou bias b # cálculo da entrada para a função de ativação # selecção da função de ativação # retorna a ativação calculada Ativado_atual e a matriz intermediária Saida # memoria temporaria para a retropropagacao # O vetor X é a ativação para a camada 0 # iterações para as camadas # a numeração das camadas começa de 1 # utiliza a ativação da iteração anterior # extrai a função de ativação para a camada atual # extrai os pesos da camada atual # extrai o bias para a camada atual # cálculo da ativação para a camada atual # salca os valores calculados na memória # retorna o vetor predito e um dicionário contendo os valores intermediários #Retropropagação para melhoria da rede # iterações pelas camadas # numero_de_exemplos # numero de exemplos #m = Y.shape[1] # para garantir que os dois vetores tenham a mesma dimensão # inicia o algoritmo de gradiente descendente # Função de ativação para a camada atual # número de exemplos # seleção função de ativação # derivada da função de ativação # derivada da matriz de Pesos # derivada do vetor b # derivada da matriz A_anterior #Função para definir o treino # Inicia os parâmetros da rede neural # Listas que vão guardar o progresso da aprendizagem da rede # Atualiza a cada época # Propaga a rede - Foward propagation # calcula as métricas e salva nas listas de história # Retropropagação - Backpropagation # Atualiza os pesos #Split dos dados para treino e teste #Treino # Treinamento #Gráfico de treinamento # Previsão # Previsão #Gráfico de previsão É possivel notar que o modelo não respondeu bem para eventos extremos #Agregação dos resultados e ajustes #Ajuste de valores zero, o modelo superestimou o valor de zero