<jupyter_start><jupyter_text>LAB: Comparação de modelos  IntroduçãoNeste lab, vamos comparar o rendimento de todos os modelos que aprendemos até agora, utilizando o [conjunto de dados sobre avaliação de carros](https://archive.ics.uci.edu/ml/machine-learning-databases/car/). Já estamos bem familiarizados com esse conjunto de dados. Em particular, vamos usar uma divisão treino-teste do conjunto de dados para observar as seguintes métricas:- accuracy score- confusion matrix- classification reportPara os seguintes modelos:- KNN- KNN + Bagging- Regressão logística- Árvores de decisão- Support Vector Machines- Random Forest &amp; Extra Trees  Exercício Requisitos1. Preparar os dados: codificar features, pré-processar- Definir funções úteis para tarefas repetitivas- KNN    1. Avaliar o rendimento de KNN    - Avaliar o rendimento de Bagging + KNN- Avaliar o rendimento da regressão logística- Avaliar o rendimento de árvores de decisão- Avaliar o rendimento de Support Vector Machines- Avaliar o rendimento de Random Forest &amp; Extra Trees- Comparação final dos modelos**Extra:**- Repetir a análise usando uma codificação one hot para as features categóricas em lugar do mapeamento a valores inteiros. Os resultados mudam?  Outros recursos- [Conjunto de dados sobre avaliação de carros](http://archive.ics.uci.edu/ml/datasets/Car+Evaluation)- [Bagging Classifier](http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.BaggingClassifier.html)- [Grid Search](http://scikit-learn.org/stable/modules/grid_search.html)  1. Preparação dos dadosO [conjunto de dados sobre avaliação de carros](https://archive.ics.uci.edu/ml/machine-learning-databases/car/) está na pasta datasets. Você já deveria estar familiarizado com ele.1. Ler os dados em um dataframe do Pandas- Codificar adequadamente as features categóricas: definir um mapeamento que preserve a ordem (designando números menores a palavras que indiquem quantidades menores)- Separar as features da variável-alvo em X e y<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
df = pd.read_csv('car.csv') #Revisar o caminho do arquivo
df.head()
print (df.buying.unique())
print (df.maint.unique())
print (df.lug_boot.unique())
print (df.safety.unique())
print (df.acceptability.unique())
print (df.persons.unique())
print (df.doors.unique())
map1 = {'low':1,
        'med':2,
        'high':3,
        'vhigh':4}

map2 = {'small':1,
        'med':2,
        'big':3}

map3 = {'unacc':1,
        'acc':2,
        'good':3,
        'vgood':4}

map4 = {'2': 2,
        '4': 4,
        'more': 5}

map5 = {'2': 2,
        '3': 3,
        '4': 4,
        '5more': 5}
features = [c for c in df.columns if c != 'acceptability']
dfn = df.copy()

dfn.buying= df.buying.map(map1)
dfn.maint= df.maint.map(map1)
dfn.lug_boot = df.lug_boot.map(map2)
dfn.persons = df.persons.map(map4)
dfn.doors = df.doors.map(map5)
dfn.safety = df.safety.map(map1)
dfn.acceptability = df.acceptability.map(map3)

X = dfn[features]
y = dfn['acceptability']
X.head()
dfn.info()<jupyter_output><class 'pandas.core.frame.DataFrame'>
RangeIndex: 1728 entries, 0 to 1727
Data columns (total 7 columns):
buying           1728 non-null int64
maint            1728 non-null int64
doors            1728 non-null int64
persons          1728 non-null int64
lug_boot         1728 non-null int64
safety           1728 non-null int64
acceptability    1728 non-null int64
dtypes: int64(7)
memory usage: 94.6 KB<jupyter_text>2. Preparação útilSendo que vamos comparar vários modelos, é conveniente escrever funções auxiliares.1. Separar X e y entre treino / teste, usando 30% como set de teste, e designando `random_state=42`    - Conferir a mistura e estratificação dos dados2. Definir uma função chamada `evaluate_model`, para treinar o modelo com o set de treino e avaliá-lo com o set de teste. E para calcular:    - accuracy score    - confusion matrix    - classification report3. Criar um dicionário global para armazenar os diferentes modelos, para uso posterior.<jupyter_code>from sklearn.model_selection import train_test_split, KFold
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix, classification_report

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

def evaluate_model(model):
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    
    a = accuracy_score(y_test, y_pred)
    
    cm = confusion_matrix(y_test, y_pred)
    cr = classification_report(y_test, y_pred)
    
    print (cm)
    print (cr)
    
    return a

all_models = {}<jupyter_output><empty_output><jupyter_text>3.a KNNComeçar com `KNeighborsClassifier`.1. Criar um modelo KNN- Avaliar seu rendimento com a função definida previamente- Procurar o valor ótimo de K com Grid Search    - Tenha cuidado ao realizar a validação cruzada no Grid Search<jupyter_code>from sklearn.neighbors import KNeighborsClassifier

a = evaluate_model(KNeighborsClassifier())
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
params = {'n_neighbors': range(2,60)}
gsknn = GridSearchCV(KNeighborsClassifier(),params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsknn.fit(X, y)
gsknn.best_params_
gsknn.best_score_
evaluate_model(gsknn.best_estimator_)
all_models['knn'] = {'model': gsknn.best_estimator_,
'score': gsknn.best_score_}<jupyter_output><empty_output><jupyter_text>3.b Bagging + KNNApós achar o K ótimo, vamos colocar `KNeighborsClassifier` em um BaggingClassifier e ver se a pontuação melhora.1. Usar o modelo KNN em um Bagging Classifier- Avaliar o rendimento- Fazer um Grid Search só nos parâmetros do Bagging Classifier<jupyter_code>from sklearn.ensemble import BaggingClassifier
baggingknn = BaggingClassifier(KNeighborsClassifier())
evaluate_model(baggingknn)
bagging_params = {'n_estimators': [10, 20],
'max_samples': [0.7, 1.0],'max_features': [0.7, 1.0],'bootstrap_features': [True, False]}

gsbaggingknn = GridSearchCV(baggingknn,
bagging_params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsbaggingknn.fit(X, y)
gsbaggingknn.best_params_
all_models['gsbaggingknn'] = {'model': gsbaggingknn.best_estimator_,
'score': evaluate_model(gsbaggingknn.best_estimator_)}<jupyter_output>[[357   5   1   0]
 [  9 106   0   0]
 [  0   7  12   2]
 [  0   2   0  18]]
             precision    recall  f1-score   support

          1       0.98      0.98      0.98       363
          2       0.88      0.92      0.90       115
          3       0.92      0.57      0.71        21
          4       0.90      0.90      0.90        20

avg / total       0.95      0.95      0.95       519<jupyter_text>4. Regressão LogísticaAgora vamos ver se a regressão logística funciona melhor1. Iniciar uma regressão logística e avaliar- Buscar os parâmetros ótimos com Grid Search- Ver se o Bagging melhora o resultado<jupyter_code>from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
all_models['lr'] = {'model': lr,
'score': evaluate_model(lr)}
params = {'C': [0.001, 0.01, 0.1, 1.0, 10.0, 100.0],
'penalty': ['l1', 'l2']}
gslr = GridSearchCV(lr,
params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gslr.fit(X, y)

print (gslr.best_params_)
print (gslr.best_score_)

all_models['gslr'] = {'model': gslr.best_estimator_,
'score': evaluate_model(gslr.best_estimator_)}
gsbagginglr = GridSearchCV(BaggingClassifier(gslr.best_estimator_),
bagging_params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsbagginglr.fit(X, y)

print (gsbagginglr.best_params_)
print (gsbagginglr.best_score_)

all_models['gsbagginglr'] = {'model': gsbagginglr.best_estimator_,
'score': evaluate_model(gsbagginglr.best_estimator_)}<jupyter_output>{'bootstrap_features': False, 'max_features': 1.0, 'max_samples': 1.0, 'n_estimators': 20}
0.831018518519
[[344  14   4   1]
 [ 50  62   3   0]
 [  3  15   2   1]
 [  0   8   0  12]]
             precision    recall  f1-score   support

          1       0.87      0.95      0.91       363
          2       0.63      0.54      0.58       115
          3       0.22      0.10      0.13        21
          4       0.86      0.60      0.71        20

avg / total       0.79      0.81      0.79       519<jupyter_text>5. Árvores de decisãoVamos conferir o rendimento das árvores de decisão1. Criar uma árvore de decisão e avaliá-la- Buscar os parâmetros ótimos com Grid Search- Ver se o Bagging melhora o resultado<jupyter_code>from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier()
all_models['dt'] = {'model': dt,
'score': evaluate_model(dt)}
params = {'criterion': ['gini', 'entropy'],
'splitter': ['best', 'random'],'max_depth': [None, 5, 10],'min_samples_split': [2, 5],'min_samples_leaf': [1, 2, 3]}
gsdt = GridSearchCV(dt,
params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsdt.fit(X, y)
print (gsdt.best_params_)
print (gsdt.best_score_)

all_models['gsdt'] = {'model': gsdt.best_estimator_,
'score': evaluate_model(gsdt.best_estimator_)}
gsbaggingdt = GridSearchCV(BaggingClassifier(gsdt.best_estimator_),
bagging_params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsbaggingdt.fit(X, y)

print (gsbaggingdt.best_params_)
print (gsbaggingdt.best_score_)

all_models['gsbaggingdt'] = {'model': gsbaggingdt.best_estimator_,
'score': evaluate_model(gsbaggingdt.best_estimator_)}<jupyter_output>{'bootstrap_features': False, 'max_features': 1.0, 'max_samples': 1.0, 'n_estimators': 20}
0.96875
[[360   2   1   0]
 [  7 106   1   1]
 [  1   4  14   2]
 [  0   1   0  19]]
             precision    recall  f1-score   support

          1       0.98      0.99      0.98       363
          2       0.94      0.92      0.93       115
          3       0.88      0.67      0.76        21
          4       0.86      0.95      0.90        20

avg / total       0.96      0.96      0.96       519<jupyter_text>6. Support Vector MachinesVamos analisar o funcionamento de SVM1. Criar um SVM e avaliar- Buscar os parâmetros ótimos com Grid Search- Ver se o Bagging melhora o resultado<jupyter_code>from sklearn.svm import SVC

svm = SVC()
all_models['svm'] = {'model': svm,
'score': evaluate_model(svm)}
params = {'C': [0.01, 0.1, 1.0, 10.0, 30.0, 100.0],
'gamma': ['auto', 0.1, 1.0, 10.0],'kernel': ['linear', 'rbf']}

gssvm = GridSearchCV(svm,
params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gssvm.fit(X, y)
print (gssvm.best_params_)
print (gssvm.best_score_)

all_models['gssvm'] = {'model': gssvm.best_estimator_,
'score': evaluate_model(gssvm.best_estimator_)}
gsbaggingsvm = GridSearchCV(BaggingClassifier(gssvm.best_estimator_),
bagging_params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsbaggingsvm.fit(X, y)

print (gsbaggingsvm.best_params_)
print (gsbaggingsvm.best_score_)

all_models['gsbaggingsvm'] = {'model': gsbaggingsvm.best_estimator_,
'score': evaluate_model(gsbaggingsvm.best_estimator_)}<jupyter_output>{'bootstrap_features': False, 'max_features': 1.0, 'max_samples': 1.0, 'n_estimators': 20}
0.982060185185
[[363   0   0   0]
 [  5 110   0   0]
 [  0   3  16   2]
 [  0   0   0  20]]
             precision    recall  f1-score   support

          1       0.99      1.00      0.99       363
          2       0.97      0.96      0.96       115
          3       1.00      0.76      0.86        21
          4       0.91      1.00      0.95        20

avg / total       0.98      0.98      0.98       519<jupyter_text>7. Random Forest &amp; Extra TreesFinalmente, vamos ver o funcionamento de Random Forest e Extra Trees1. Criar RF e ET e avaliá-los- Buscar os parâmetros ótimos com Grid Search<jupyter_code>from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier

rf = RandomForestClassifier()
all_models['rf'] = {'model': rf,
'score': evaluate_model(rf)}


et = ExtraTreesClassifier()
all_models['et'] = {'model': et,
'score': evaluate_model(et)}
params = {'n_estimators':[3, 5, 10, 50],
'criterion': ['gini', 'entropy'],'max_depth': [None, 3, 5],'min_samples_split': [2,5],'class_weight':[None, 'balanced']}

gsrf = GridSearchCV(RandomForestClassifier(n_jobs=-1),
params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gsrf.fit(X, y)
print (gsrf.best_params_)
print (gsrf.best_score_)

all_models['gsrf'] = {'model': gsrf.best_estimator_,
'score': evaluate_model(gsrf.best_estimator_)}
gset = GridSearchCV(ExtraTreesClassifier(n_jobs=-1),
params, n_jobs=-1,cv=KFold(n_splits=3, shuffle=True))
gset.fit(X, y)
print (gset.best_params_)
print (gset.best_score_)

all_models['gset'] = {'model': gset.best_estimator_,
'score': evaluate_model(gset.best_estimator_)}<jupyter_output>{'class_weight': None, 'criterion': 'gini', 'max_depth': None, 'min_samples_split': 2, 'n_estimators': 50}
0.974537037037
[[359   4   0   0]
 [  3 110   1   1]
 [  0   4  16   1]
 [  0   1   0  19]]
             precision    recall  f1-score   support

          1       0.99      0.99      0.99       363
          2       0.92      0.96      0.94       115
          3       0.94      0.76      0.84        21
          4       0.90      0.95      0.93        20

avg / total       0.97      0.97      0.97       519<jupyter_text>8. Comparação de modelosVamos comparar os resultados dos diferentes modelos.1. Fazer um gráfico de barras dos resultados dos melhores modelos. Qual o vencedor?- Voltar a avaliar todos os modelos com uma validação cruzada estratificada de 3-fold- Fazer um gráfico de barras que mostre o valor médio e desvio do resultado da validação cruzada. O vencedor continua sendo o mesmo?<jupyter_code>scores = pd.DataFrame([(k, v['score']) for k, v in all_models.items()],
columns=['model', 'score']).set_index('model').sort_values('score', ascending=False)

scores.plot(kind='bar')
plt.ylim(0.6, 1.1)

scores
from sklearn.model_selection import cross_val_score, StratifiedKFold

def retest(model):
    scores = cross_val_score(model, X, y,
cv=StratifiedKFold(n_splits=3, shuffle=True),n_jobs=-1)    m = scores.mean()
    s = scores.std()
    
    return m, s

for k, v in all_models.items():
    cvres = retest(v['model'])
    print (k), 
    all_models[k]['cvres'] = cvres
    
cvscores = pd.DataFrame([(k, v['cvres'][0], v['cvres'][1] ) for k, v in all_models.items()],
columns=['model', 'score', 'error']).set_index('model').sort_values('score', ascending=False)

fig, ax = plt.subplots()
rects1 = ax.bar(range(len(cvscores)), cvscores.score,
yerr=cvscores.error,tick_label=cvscores.index)
ax.set_ylabel('Scores')
plt.xticks(rotation=70)
plt.ylim(0.6, 1.1)

cvscores<jupyter_output><empty_output><jupyter_text>ExtraJá codificamos os dados com um mapa que preservava a ordem.Como os resultados mudariam se codificássemos os dados categóricos usando `pd.get_dummies` ou `OneHotEncoder` para codificá-los como variáveis binárias?1. Repetir a análise para esse cenário. É melhor?- Experimentar com outros modelos ou outros parâmetros. Você consegue obter o melhor rendimento da aula?<jupyter_code>from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import make_pipeline

all_modelsoh={}

onehotpipe = make_pipeline(OneHotEncoder() , dt)

all_modelsoh['onehotpipe'] = {'model': onehotpipe,
'score': evaluate_model(onehotpipe)}
# A pontuação da árvore de decisão cai quando empregamos OneHotEncoder em lugar de uma escala numérica.<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11510556245506243, 'fraction_numerical': 0.04784626446172952, 'mean_word_length': 3.6617915904936016, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '562455', 'license': 'MIT', 'n_tokens_mistral': 6038, 'n_tokens_neox': 5661, 'n_words': 1447, 'path': '03-machine-learning-tabular-crossection/15 - Explaining Black Box Models/other/comparando_diferentes_modelos_metricas.ipynb', 'repo_name': 'abefukasawa/datascience_course', 'size': '15299'}