import pandas as pd
import numpy as np
from sklearn import svm, datasets
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn import svm

df = pd.read_csv('evasao.csv')
df.head()

df.describe()

features = df[['periodo','bolsa','repetiu','ematraso','disciplinas','faltas']]
labels = df[['abandonou']]

features.head()


labels.head()

"""
Explanation: Churn prediction
Evasão escolar
Churn prediction é um tipo de trabalho muito comum em data science, sendo uma questão de classificação binária. Trada-se do possível abandono de um cliente ou de um aluno. Analisamos o dataset e tentamos prever as situações de risco de abandono, para tomarmos medidas proativas de fidelização.
Para este exemplo, usamos um dataset real, porém desidentificado, de uma pesquisa que realizei há algum tempo, a pedido de uma instituição de ensino, para identificar os alunos com maior probabilidade de abandorarem o curso.
Da população de alunos, foram eliminados os que possuem percentual de bolsa de estudos igual ou superior a 50%, pois trata-se de situações especiais. Os dados são coletados semanalmente, a partir dos resultados das primeiras provas de cada período.
End of explanation
"""


X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.33, random_state=42)

"""
Explanation: Separação dos dados
Precisamos separar os dados de teste dos dados de treino, virtualmente esquecendo que os dados de testes existem!
End of explanation
"""


padronizador = StandardScaler().fit(X_train[['periodo', 'bolsa', 'repetiu', 'disciplinas', 'faltas']])
X_train_1 = pd.DataFrame(padronizador.transform(X_train[['periodo', 'bolsa', 'repetiu', 'disciplinas', 'faltas']]))
X_train_scaled = pd.DataFrame(X_train_1)
X_train_scaled = X_train_scaled.assign(e = X_train['ematraso'].values)
X_train_scaled.head()


"""
Explanation: Padronização dos atributos
Como vamos usar SVM, precisamos colocar os atributos numéricos na mesma escala, e codificar os atributos de categoria. Temos um atributo de categoria: 'ematraso' e ele possui apenas dois valores: zero e um, logo, já está codificado. Se fossem múltiplos valores, teríamos que usar algo como o OneHotEncoder para transformá-lo em variáveis binárias.
End of explanation
"""


modeloLinear = svm.SVC(kernel='linear') 
modeloLinear.fit(X_train_scaled.values, y_train.values.reshape(201,))
modeloLinear.score(X_train_scaled.values, y_train.values.reshape(201,))

"""
Explanation: Kernel linear
End of explanation
"""


modeloRbf = svm.SVC(kernel='rbf',C=2) 
modeloRbf.fit(X_train_scaled.values, y_train.values.reshape(y_train.size))
modeloRbf.score(X_train_scaled.values, y_train.values.reshape(y_train.size))

"""
Explanation: Kernel RBF com C=2 e sem gamma
End of explanation
"""


modeloRbfg10 = svm.SVC(kernel='rbf',C=1,gamma=10) 
modeloRbfg10.fit(X_train_scaled.values, y_train.values.reshape(y_train.size))
modeloRbfg10.score(X_train_scaled.values, y_train.values.reshape(y_train.size))

"""
Explanation: Kernel RBF com C=1 e gamma=10
End of explanation
"""


modeloPoly = svm.SVC(kernel='poly',C=2,gamma=10) 
modeloPoly.fit(X_train_scaled.values, y_train.values.reshape(y_train.size))
modeloPoly.score(X_train_scaled.values, y_train.values.reshape(y_train.size))

"""
Explanation: Kernel Poly com C=2 e gamma=10
End of explanation
"""


modeloSig = svm.SVC(kernel='sigmoid',C=2,gamma=100) 
modeloSig.fit(X_train_scaled.values, y_train.values.reshape(y_train.size))
modeloSig.score(X_train_scaled.values, y_train.values.reshape(y_train.size))

"""
Explanation: Kernel Sigmoid com C=2 e gamma=100
End of explanation
"""


X_test_1 = padronizador.transform(X_test[['periodo', 'bolsa', 'repetiu', 'disciplinas', 'faltas']])
X_test_1 = pd.DataFrame(padronizador.transform(X_test[['periodo', 'bolsa', 'repetiu', 'disciplinas', 'faltas']]))
X_test_scaled = pd.DataFrame(X_test_1)
X_test_scaled = X_test_scaled.assign(e = X_test['ematraso'].values)
X_test_scaled.head()

"""
Explanation: Nem sempre o modelo que tem melhor score é o modelo que dá a melhor previsão para dados ainda não vistos. Pode ser o caso de "overfitting". Vamos testar vários tipos de kernel e combinações de parâmetros.
End of explanation
"""


predicoes = modeloRbfg10.predict(X_test_scaled)
printResults(predicoes)

predicoesGamma1 = modeloRbf.predict(X_test_scaled)
printResults(predicoesGamma1)

"""
Explanation: A melhor maneira de testar é comparar os resultados um a um.
End of explanation
"""


predicoesPoly = modeloPoly.predict(X_test_scaled)
printResults(predicoesPoly)

predicoesSig = modeloSig.predict(X_test_scaled)
printResults(predicoesSig)

def printResults(pr):
    acertos = 0
    errosAbandono = 0
    errosPermanencia = 0
    for n in range(0,len(pr)):
        if pr[n] == y_test.values.flatten()[n]:
            acertos = acertos + 1
        else:
            if pr[n] == 0:
                errosAbandono = errosAbandono + 1
            else:
                errosPermanencia = errosPermanencia + 1
    print('Acertos',acertos)
    print('Percentual',acertos / len(pr))
    print('Erramos ao dizer que o aluno abandonou', errosAbandono)
    print('Erramos ao dizer que o aluno permaneceu', errosPermanencia)

"""
Explanation: Este foi o melhor resultado que conseguimos.
End of explanation
"""


