Churn Prediction in Python con analisi del sentiment con NLTK

Nel campo della data science, ci sono molte applicazioni pratiche che possono aiutare le aziende a migliorare la loro strategia di business. Una di queste applicazioni è quella che si chiama “churn prediction”, ovvero la previsione dei clienti che potrebbero abbandonare un servizio o prodotto.
Intro
La predizione di “abbandono” è una delle strategie più importanti per le aziende che desiderano mantenere una base di clienti fedeli e ridurre i costi associati all’acquisizione di nuovi clienti. Utilizzare l’analisi del sentiment per prevedere il churn può essere particolarmente efficace, poiché consente di comprendere meglio le emozioni e le opinioni dei clienti nei confronti del servizio o prodotto offerto. In questo tutorial, esploreremo come utilizzare Python per eseguire una predizione di churn basata sull’analisi del sentiment.
Passaggi per la predizione del churn con Python e NLTK
Requisiti
Assicurati di avere installato le seguenti librerie Python:
- pandas
- numpy
- nltk
- pycaret
- ydata-profiling
Tieni conto che nel caso di pycaret e ydata-profiling, la compatibilità con la versione di Python in uso potrebbe essere limitata. Si consiglia di utilizzare Python 3.8 o 3.11 al massimo per evitare problemi di compatibilità.
Passo 1: Import delle librerie
Per iniziare, è necessario importare tutte le librerie Python necessarie per l’analisi dei dati e la predizione del churn. Queste librerie includono pandas per la manipolazione dei dati, numpy per le operazioni numeriche, nltk per l’analisi del sentiment e pycaret per la creazione e la valutazione dei modelli di classificazione.
import pandas as pd
import numpy as np
from ydata_profiling import ProfileReport
from pycaret.classification import *
import matplotlib.pyplot as plt
import random
import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
Passo 2: Download del lexicon NLTK
Per utilizzare l’analisi del sentiment con NLTK, è necessario scaricare il lexicon VADER, che è uno strumento popolare per l’analisi del sentiment dei testi in inglese. Il lexicon, in altre parole, è un insieme di parole con punteggi di sentiment associati. VADER è quello più adatto per l’analisi del sentiment in contesti sociali e di recensioni, ma ne esistono altri per altre lingue e contesti, come TextBlob, SentiWordNet, ecc.
nltk.download('vader_lexicon')
Come funziona VADER, e cos’è: parliamo di un modello pre-addestrato di analisi del sentiment basato su regole che utilizza un dizionario di parole con punteggi di sentiment associati. VADER è progettato per essere efficace nell’analisi del sentiment in contesti sociali e di recensioni, ed è particolarmente utile per testi brevi come tweet, commenti sui social media e recensioni di prodotti. Funziona grazie a un insieme di regole che tengono conto dell’analisi sintattica e semantica della lingua, come l’uso di punteggiatura, emoticon e intensificatori (ad esempio, “molto”, “estremamente”) per calcolare un punteggio di sentiment complessivo per un dato testo.
Passo 3: Generazione di dati sintetici
Poiché non sempre si dispone di dati reali, possiamo generare dati sintetici per testare il nostro modello. Questi dati includono informazioni come il numero di interazioni, il tempo trascorso, il numero di sessioni, i giorni dall’ultimo accesso e il feedback dei clienti. Teniamo presente che, se abbiamo a disposizione un dataset reale, possiamo saltare questo passaggio e caricare direttamente i dati.
def generate_synthetic_churn_data(n_users=1000):
np.random.seed(42)
random.seed(42)
user_ids = [f"user_{i}" for i in range(n_users)]
interactions = np.random.poisson(5, n_users)
time_spent = np.random.normal(loc=50, scale=10, size=n_users)
number_of_sessions = np.random.poisson(3, n_users)
days_since_last_login = np.random.randint(0, 30, n_users)
avg_interactions_per_session = interactions / np.maximum(1, number_of_sessions)
feedback = []
churned = []
for i in range(n_users):
if time_spent[i] > 60:
feedback.append("positive")
churned.append("no")
elif days_since_last_login[i] > 20 and number_of_sessions[i] < 2:
feedback.append("negative")
churned.append("yes")
else:
feedback.append("neutral")
churned.append(np.random.choice(["yes", "no"], p=[0.8, 0.2]))
synthetic_data = pd.DataFrame({
"user_id": user_ids,
"interactions": interactions,
"time_spent": time_spent,
"number_of_sessions": number_of_sessions,
"days_since_last_login": days_since_last_login,
"avg_interactions_per_session": avg_interactions_per_session,
"feedback": feedback,
"churned": churned
})
return synthetic_data
All’interno di questo passaggio, andiamo infatti a definire una funzione che genera un DataFrame con dati sintetici per 1000 utenti, includendo variabili che potrebbero influenzare il churn, come ad esempio il numero di interazioni e il feedback nel contesto di utilizzo di un servizio. Per questa ragione, nella generazione di questo dataset sono state incluse variabili come il numero di sessioni e il tempo trascorso, che possono essere utili per la predizione del churn. Per dare una “spinta” al dataset, nel caso della generazione del feedback e del churn, sono state definite delle regole basate su alcune condizioni (ad esempio, se il tempo trascorso è superiore a 60 minuti, il feedback è positivo e il churn è “no”). Sono del tutto arbitrarie, ma servono a creare una relazione tra le variabili che possa essere utile per il modello di predizione e a renderlo più realistico.
> La cosa importante in questo passaggio è l'avere a disposizione un dataset, in formato .csv o simili, che contenga le informazioni necessarie per la predizione del churn. Se si dispone di un dataset reale, è possibile caricarlo direttamente utilizzando `pd.read_csv()` o altre funzioni di caricamento dei dati.
Non esiste un numero giusto o sbagliato di variabili da includere nel dataset, ma è importante che queste variabili siano rilevanti per il contesto di utilizzo del servizio o prodotto. L'unico fattore da considerare, per questo progetto, è che all'interno del dataset sia presente l'informazione relativa al feedback dei clienti, in modo da poter eseguire l'analisi del sentiment, e l'informazione relativa al churn (se il cliente ha abbandonato o meno il servizio). Tieniamo ancore presente che, in un contesto reale, il dataset potrebbe essere molto più complesso e includere molte più variabili, e quello generato potrebbe dare risultati non del tutto realistici.
### Passo 4: Analisi del sentiment
Siamo al clue del progetto: adesso dobbiamo utilizzare i nostri dati per analizzare il sentiment del feedback. Come anticipato, utilizziamo VADER per calcolare il punteggio del sentiment per ogni feedback ricevuto. Questo punteggio ci aiuta a comprendere se il feedback è positivo, neutrale o negativo.
```python
sid = SentimentIntensityAnalyzer()
synthetic_data["sentiment"] = synthetic_data["feedback"].apply(lambda x: sid.polarity_scores(x)["compound"])
# Codifica dei dati per la predizione
synthetic_data_encoded = synthetic_data.drop(columns=['user_id'])
synthetic_data_encoded = pd.get_dummies(synthetic_data_encoded, columns=["feedback"], drop_first=True)
Come visto, per farlo, utilizziamo la funzione polarity_scores di VADER per calcolare il punteggio del sentiment per ogni feedback. Il punteggio restituito è un valore compreso tra -1 (molto negativo) e 1 (molto positivo). Inoltre, aggiungiamo questo punteggio come una nuova colonna nel nostro DataFrame, così da poterlo utilizzare successivamente per la predizione del churn. L’oggetto SentimentIntensityAnalyzer() viene utilizzato per creare un’istanza dell’analizzatore di sentiment VADER, che viene poi utilizzata per calcolare i punteggi di sentiment per ogni feedback nel dataset.
Passo 5: Generazione di un report di esplorazione dei dati (EDA)
Quando si studiano i dati, è sempre una buona pratica eseguire un’analisi esplorativa dei dati per comprendere meglio le caratteristiche del dataset. Nel contesto della data science, si tratta di un passaggio fondamentale per identificare eventuali problemi nei dati, come valori mancanti o anomalie, e per comprendere le relazioni tra le variabili.
Per comprendere meglio i nostri dati, generiamo un report EDA che include statistiche descrittive e visualizzazioni dei dati.
profile = ProfileReport(synthetic_data_encoded, title="Synthetic Data EDA Report", explorative=True)
profile.to_file("synthetic_data_eda_report.html")
print("EDA report has been generated and saved as 'synthetic_data_eda_report.html'.")
Per farlo, abbiamo usato la libreria ydata_profiling, che consente di generare report EDA in modo semplice e veloce. Il report viene salvato come file HTML, che può essere aperto in un browser per una visualizzazione interattiva.

Passo 6: Test del modello di predizione del churn
A questo punto, configuriamo e confrontiamo diversi modelli di classificazione per trovare il migliore per prevedere il churn. Utilizziamo la libreria pycaret per semplificare il processo, dal momento che consente di eseguire rapidamente il setup dei dati, confrontare i modelli e valutarne le prestazioni.
synthetic_data_encoded["churned"] = synthetic_data_encoded["churned"].astype(str)
clf = setup(data=synthetic_data_encoded, target="churned", session_id=42, normalize=True,
transformation=True, remove_outliers=True, fix_imbalance=True, html=False, verbose=False, use_gpu=False)
best_model = compare_models(sort="F1")
Vediamo passo passo cosa fa questo codice:
- Convertiamo la colonna “churned” in stringa per assicurarci che sia trattata come una variabile categorica, così che sia più facile per i modelli di classificazione lavorarci.
- Configuriamo l’ambiente di
pycaretutilizzando la funzionesetup, specificando il dataset, la variabile target e alcune opzioni per la normalizzazione, la trasformazione dei dati, la rimozione degli outlier e il bilanciamento delle classi. - Confrontiamo diversi modelli di classificazione utilizzando la funzione
compare_modelsdella libreriapycaret, ordinandoli in base al punteggio F1, che è una metrica importante per valutare le prestazioni dei modelli di classificazione, soprattutto in presenza di classi sbilanciate.
Infine, valutiamo le prestazioni del modello migliore utilizzando metriche come precisione, recall e F1-score, sempre utilizzando le funzionalità di pycaret.
evaluate_model(best_model)
Passo 7: Predizione del churn
Ora che abbiamo selezionato il modello migliore, possiamo utilizzarlo per fare predizioni sul churn. Usiamo la funzione predict_model di pycaret per ottenere le predizioni sul nostro dataset.
predictions = predict_model(best_model, data=synthetic_data_encoded)
print(predictions[['Label', 'Score']].head(10)) # Visualizza le prime 10 predizioni
Immaginiamo quindi di avere un dataset di nuovi clienti per i quali vogliamo prevedere il churn. Possiamo utilizzare lo stesso modello per fare predizioni su questi nuovi dati.
new_customers = ... # Caricamento o generazione di nuovi dati dei clienti
new_customers["sentiment"] = new_customers["feedback"].apply(lambda x: sid.polarity_scores(x)["compound"])
new_customers_encoded = new_customers.drop(columns=['user_id'])
new_customers_encoded = pd.get_dummies(new_customers_encoded, columns=["feedback"], drop_first=True)
new_predictions = predict_model(best_model, data=new_customers_encoded)
print(new_predictions[['Label', 'Score']].head(10)) # Visualizza le
# prime 10 predizioni per i nuovi clienti
Passo 8: Engagement dei clienti (opzionale)
Ora che abbiamo preparato un modello per avere un’idea dei clienti che potrebbero abbandonare il servizio, creiamo messaggi personalizzati in base al loro feedback e al punteggio del sentiment. Possiamo quindi utilizzare una funzione come la seguente che, sulla base del feedback, del sentiment, del numero di interazioni e dei giorni dall’ultimo accesso, genera un messaggio di ri-coinvolgimento personalizzato per ogni cliente che ha abbandonato il servizio.
def create_reengagement_message(feedback, sentiment_score, interactions, days_since_last_login):
if sentiment_score 0.5:
return "Ti manchiamo! Torna e continua da dove hai lasciato con le funzionalità che ami."
elif interactions 7:
return "Sembra che tu stia perdendo qualcosa! Entra ora per reclamare un bonus speciale."
else:
return "Stiamo costantemente migliorando. Torna e dai un'altra possibilità!"
# Applicazione della funzione di messaggio di ri-coinvolgimento ai clienti che hanno abbandonato
synthetic_data["reengagement_message"] = synthetic_data.apply(
lambda x: create_reengagement_message(
x["feedback"], x["sentiment"], x["interactions"], x["days_since_last_login"]
) if x["churned"] == "yes" else None,
axis=1
)
# Visualizzazione di alcuni clienti che hanno abbandonato con i loro messaggi di ri-coinvolgimento
churned_users = synthetic_data[synthetic_data['churned'] == "yes"][['feedback', 'sentiment', 'reengagement_message']]
print(churned_users.head(10))
Conclusioni
La predizione del churn è un aspetto cruciale per le aziende che desiderano mantenere una base di clienti fedeli e ridurre i costi associati all’acquisizione di nuovi clienti. Utilizzare l’analisi del sentiment per comprendere meglio le opinioni dei clienti può aiutare a creare strategie di ri-coinvolgimento più efficaci. Questo tutorial ha mostrato come utilizzare Python e nltk per generare dati sintetici, eseguire l’analisi del sentiment e creare un modello di predizione del churn. Inoltre, ha illustrato come creare messaggi personalizzati per ri-coinvolgere i clienti che hanno abbandonato. Queste strategie possono essere adattate e migliorate ulteriormente in base alle esigenze specifiche del tuo business.








