Come creare un trasformatore custom da inserire in una Pipeline di Sklearn

Una delle funzionalità più usate e apprezzate di Scikit-Learn sono le pipeline. Sebbene il loro utilizzo sia optional, quest'ultime possono essere utilizzate per rendere il nostro codice più pulito e facile da mantenere. Le pipeline accettano come input degli estimators, che non sono altro che delle classi che si ereditano da sklearn.base.BaseEstimator e che contengono i metodi fit e transform. Questo ci permette di personalizzare le pipeline con funzionalità che Sklearn non offre di default.

Parleremo dei transformer, degli oggetti che applicano una trasformazione su un input. La classe dalla quale erediteremo è TransformerMixin, ma è possibile estendere anche da ClassifierMixin, RegressionMixin, ClusterMixin e altri per creare un estimator personalizzato. Leggere qui per tutte le opzioni disponibili.

Lavoreremo con un dataset di dati testuali, sulla quale vogliamo applicare delle trasformazioni quali:

  • preprocessing del testo
  • vettorizzazione con TF-IDF
  • creazione di feature aggiuntive a scopo di esempio come sentiment, numero di caratteri, numero di frasi

Questo verrà fatto attraverso l'utilizzo di Pipeline e FeatureUnion, una classe di Sklearn che unisce i feature set provenienti da diverse sorgenti.

Il Dataset

Useremo il dataset fornito da Sklearn, 20newsgroups, per avere rapido accesso ad un corpus di dati testuali. A scopo dimostrativo, userò solo un campione di 10 testi ma l'esempio può essere esteso a qualsiasi numero di testi.

Importiamo il dataset con Python

Creazione di feature testuali

Costruiremo il feature set conterrà queste informazioni

  • vettorizzazione con TF-IDF dopo aver applicato preprocessing
  • sentiment con NLTK.Vader
  • numero di caratteri nel testo
  • numero di frasi nel testo

Il nostro processo, senza usare pipeline, sarebbe quello di applicare sequenzialmente tutti questi step con blocchi di codice separato. La bellezza delle pipeline è che la sequenzialità viene mantenuta in un solo blocco di codice - la pipeline stessa diventa un estimator, in grado di eseguire tutte le operazioni programmate in una sola istruzione.

Creiamo le nostre funzioni

Il nostro obiettivo è quello di creare un feature set unico in modo da addestrare un modello su un qualche task. Useremo le Pipeline e FeatureUnion per mettere insieme le nostre matrici.

Come unire le feature provenienti da sorgenti diverse

La vettorizzazione TF-IDF creerà una matrice sparsa che avrà dimensioni n_documenti_nel_corpus * n_features, il sentiment sarà un singolo numero, come anche l'output di n_chars e n_sentences. Andremo a prendere gli output di ognuno di questi step e a creare una matrice singola che li conterrà tutti, in modo da poter addestrare un modello su tutte le feature che abbiamo ingegnerizzato. Partiremo da una rappresentazione del genere

Fino a giungere a questo

Il feature set verrà usato come vettore di addestramento del nostro modello.

Classi che ereditano da BaseEstimator e TransformerMixin

Per poter mettere giù il nostro processo, occorre definire le classi e cosa faranno nella pipeline. Iniziamo col creare un DummyEstimator, dal quale andremo ad ereditare init, fit e transform. Il DummyEstimator è una classe comoda che ci evita la scrittura di diverso codice.

DummyEstimator sarà ereditato da quattro classi, Preprocessor, SentimentAnalysis, NChars, NSentences e FromSparseToArray.

Com'è possibile vedere, DummyEstimator ci permette di definire solo la funzione transform, poiché ogni altra classe eredita init e fit proprio da DummyEstimator.

Vediamo ora come implementare la pipeline di vettorizzazione, che terrà conto del preprocessing dei nostri testi.

Non resta che applicare FeatureUnion per mettere insieme i pezzi

Applichiamo fit_transform sul nostro corpus e vediamo l'output

L'output sembra essere corretto! Non è molto chiaro, però. Concludiamo il tutorial con l'inserimento in dataframe del feature set combinato

Il risultato è il seguente (qui ho troncato il risultato per questioni di leggibilità)

Ora abbiamo un dataset pronto per essere fornito a qualsiasi modello per addestramento. Sarebbe utile sperimentare con StandardScaler o simili e normalizzare n_chars e n_sentences. Lascerò questo esercizio al lettore.

Codice

Andrea D'Agostino
Ciao, sono Andrea D'Agostino e sono un data scientist con 6 anni di esperienza nel campo della business intelligence. Applico tecniche statistiche e di machine learning per aiutare i clienti a trovare e risolvere problemi nei loro asset digitali e a sfruttare le debolezze dei competitor a loro vantaggio.

Sono il fondatore e l'autore di questo blog, il cui obiettivo è raccogliere le informazioni più importanti che ho imparato durante il mio percorso lavorativo e accademico al fine di poter aiutare il lettore a migliorare le sue analisi.