<jupyter_start><jupyter_text>Algoritmi Ensemble![mush](https://s3-eu-central-1.amazonaws.com/hermanns-website-2/wp-content/uploads/2018/11/09142320/florian-van-duyn-383221-unsplash_resized.jpg)[Image Credits](https://www.hermanns.com/why-mushrooms-talk-to-us/)Fino ad ora abbbiamo visto quelli che vengono detti *modelli deboli* o *weak learner*.Cosa vuol dire in sostanza. Se noi costruiamo un albero di classificazione quello è solo uno dei diversi modi che esistono per classificare quelle osservazioni. I classificatori deboli sono anche inclini ad andare in overfitting proprio perchè la loro struttura è una delle molteplici che si potrebbero generare.Una soluzione a questo problema sono i modelli ***Ensemble*** che mettono insieme più modelli deboli per generare un modello robusto al rumore. Naturalmente i costi in terminin di risorse e tempi salgono. DatasetIl dataset che useremo si chiama Mushrooms e classifica i funghi in velenosi e non velenosi. Potete trovare maggiorni informazioni sulla[ pagina dedicata dell'UCI ML.](http://archive.ics.uci.edu/ml/datasets/Mushroom)Il dataset ha oltre 8000 osservazioni e 23 variabili tutte categoriche. Faremo un minimo di conversione sulle variabili ma nessuna analisi dei dati o preprocessing.Il dataset e il codice sono presi dal [kaggle kernel a questo link](https://www.kaggle.com/drvader/random-forests-and-gradient-boosting/data).<jupyter_code>import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials

# Authenticate and create the PyDrive client.
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
link = 'https://drive.google.com/YOURFILEPATH'
fluff, id = link.split('=')

downloaded = drive.CreateFile({'id':id}) 
downloaded.GetContentFile('mushrooms.csv')
df = pd.read_csv("mushrooms.csv")
df.head()<jupyter_output><empty_output><jupyter_text>Preparazione del datasetCostruiamo la variabile di risposta binaria:* 0 non velenoso* 1 velenosoApplichiamo un OneHot Encoding su tutte le altre variabili.<jupyter_code>df["class"].replace(["e", "p"], [1, 0], inplace= True)
y = df["class"]
df.drop("class", axis = 1, inplace = True)
X = pd.get_dummies(df)
X.head()
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size= 0.25, random_state= 42)
print("Osservazioni train: ", len(X_train), "\n", "Osservazioni Test: ", len(X_test))<jupyter_output><empty_output><jupyter_text>Models**N.B. Per questioni di tempi non faremo tuning dei parametri ma potete trovare riferimenti interessanti tra i link in fondo al notebook.**  Random Forest![RandomForest](https://miro.medium.com/max/2000/1*_B5HX2whbTs3DS8M6YBD_w@2x.png)[Image Credits](https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)Il **Random Forest** è l'algoritmo che ha sicuramente il nome più affascinante di tutti.Usa una tecnica chiamata *bagging* per allenare in maniera parallela N decision tree e successivamente con un sistema di pesi (banalmente il più frequente) sceglie la classificazione finale. Dall'allenamento di N decision tree deriva il nome di questo algoritmo. BaggingIl **Bagging** (o Bootstrap aggregation) è una tecnica che si basa sul bootstrap, ovvero un ricampionamento in cui da una serie di dati vengono estratti N campioni indipendenti e ogni campione viene dato come input ad uno degli N alberi.![bootstrap](https://miro.medium.com/max/1400/1*lWnm3eJVe3uo95OcSg5jUA@2x.png)[Image Credits](https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)In questo modo ogni albero protrebbe essere differente e il risultato molto più resistente all'overfitting.Inoltre allenando più alberi in maniera indipendente vi è una selezione delle features più impattanti.<jupyter_code>from sklearn.ensemble import RandomForestClassifier

rfcl = RandomForestClassifier(n_estimators = 20, random_state = 42)

rfcl.fit(X_train, y_train)

yhat_rfcl = rfcl.predict(X_test)<jupyter_output><empty_output><jupyter_text>Gradient Boosting![boosting](https://miro.medium.com/max/2000/1*VGSoqefx3Rz5Pws6qpLwOQ@2x.png)[Image Credits](https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205) BoostingA differenza del bagging il **Boosting** è un processo iterativo che migliora la stima ad ogni passo fino ad arrivare ad un modello finale. Ad esempio vediamo questi due passi:**STEP 1**:* abbiamo una serie di dati* proviamo a fare fitting con una funziona logaritmica![step1](https://iaml.it/blog/gradient-boosting/images/P4SrKe6.png)[Image Credits](https://iaml.it/blog/gradient-boosting)**STEP 2**:* per un miglior fitting aggiungiamo una funzione seno che cattura gli andamenti oscillatori![step2](https://iaml.it/blog/gradient-boosting/images/7EUfGSi.png)[Image Credits](https://iaml.it/blog/gradient-boosting)Questo è un esempio di come funzionano gli algortimi di boosting, un processo iterativo dove ad ogni passo si cerca di migliorare il fitting.Esistono diversi algoritmi di boosting, i più utilizzati e noti sono:* AdaBoost* GradientBoost (da cui deriva [XGBoost](https://en.wikipedia.org/wiki/XGBoost) che è molto prababilmente l'algoritmo più vincente su Kaggle).<jupyter_code>from sklearn.ensemble import GradientBoostingClassifier

gbcl = GradientBoostingClassifier(n_estimators = 20, random_state = 42)

gbcl.fit(X_train, y_train)

yhat_gbcl = rfcl.predict(X_test)<jupyter_output><empty_output><jupyter_text>Stacked ClassifierGli **Stacked Ensemble Methods** sono una terza via tra le tecniche che usano il Bagging e il Boosting, infatti:* a differenza del Random Forest che usa sempre lo stesso weak learner combinano diversi modelli* a differenza dei metodi boosting che sono iterativi lavorano con i diversi modelli in paralleloil tutto mirato a costruire un meta-modello che sarà il nostro strong learner.![STACKED](https://miro.medium.com/max/1400/1*ZucZsXkOwrpY2XaPh6teRw@2x.png)[Image Credits](https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)Di seguito vedremo come costruire un semplice Stacked Classifier con Scikit-learn utilizzando:* Random Forest* Logistic Regression<jupyter_code>from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression

# nell'iperparametro estimators và inserita una lista di modelli, nel nostro caso solo uno
estimators = [('rf', RandomForestClassifier(n_estimators=20, random_state=42))]

stkcl = StackingClassifier(estimators= estimators, final_estimator=LogisticRegression(random_state=42))

stkcl.fit(X_train, y_train)

yhat_stkcl = stkcl.predict(X_test)<jupyter_output><empty_output><jupyter_text>Valutazione delle performance Curva di ROCLa curva di ROC è uno strumento per valutare i classificatori binari e consite, in termini semplici, nel rapporto tra allarmi veri e falsi allarmi.Misura la porzione dei veri positivi trovati rispetto a quella dei falsi postitivi, un valore pari a 1 corrisponde ad una perfetta classificazione.<jupyter_code>from sklearn.metrics import confusion_matrix, accuracy_score, plot_roc_curve<jupyter_output><empty_output><jupyter_text>Random Forest<jupyter_code>print(confusion_matrix(y_test, yhat_rfcl))

print("\n")

print(accuracy_score(y_test, yhat_rfcl))
plot_roc_curve(rfcl, X_test, y_test)<jupyter_output><empty_output><jupyter_text>Gradient Boosting<jupyter_code>print(confusion_matrix(y_test, yhat_gbcl))

print("\n")

print(accuracy_score(y_test, yhat_gbcl))
plot_roc_curve(gbcl, X_test, y_test)<jupyter_output><empty_output><jupyter_text>Stacked Classifier<jupyter_code>print(confusion_matrix(y_test, yhat_stkcl))

print("\n")

print(accuracy_score(y_test, yhat_stkcl))
plot_roc_curve(stkcl, X_test, y_test)<jupyter_output><empty_output><jupyter_text>Link Utili[Kaggle kernel](https://www.kaggle.com/drvader/random-forests-and-gradient-boosting/data)[Gradient Boosting - IAML](https://iaml.it/blog/gradient-boosting)[Ensemble methods: bagging, boosting and stacking](https://towardsdatascience.com/ensemble-methods-bagging-boosting-and-stacking-c9214a10a205)[Gradient Boosting with Scikit-Learn, XGBoost, LightGBM, and CatBoost](https://machinelearningmastery.com/gradient-boosting-with-scikit-learn-xgboost-lightgbm-and-catboost/)[Present The Feature Importance of A Random Forest Classifier](https://towardsdatascience.com/present-the-feature-importance-of-the-random-forest-classifier-99bb042be4cc)[Hyperparameters Optimization for LightGBM, CatBoost and XGBoost Regressors using Bayesian Optimization.](https://medium.com/analytics-vidhya/hyperparameters-optimization-for-lightgbm-catboost-and-xgboost-regressors-using-bayesian-6e7c495947a9)[StackingClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.StackingClassifier.html)<jupyter_code><jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09206736095723465, 'fraction_numerical': 0.017837358741413695, 'mean_word_length': 7.024, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 24, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '604986', 'license': 'MIT', 'n_tokens_mistral': 3267, 'n_tokens_neox': 3125, 'n_words': 763, 'path': 'machine_learning_pills/01_supervised/08_ensemble.ipynb', 'repo_name': 'nickprock/appunti_data_science', 'size': '9026'}