
Introduzione
Negli ultimi 10-15 anni, con il progresso delle tecnologie digitali, le strategie di marketing sono cambiate in modo significativo. Brand famosi e mercati più piccoli hanno raccolto una grande quantità di dati su transazioni, acquisti, preferenze, potere d’acquisto, attività di acquisto, dati demografici, recensioni, ecc. Tutti questi dati possono aiutare i marketer a capire il comportamento dei clienti nelle diverse fasi, dall’intenzione di acquistare qualcosa, all’acquisto effettivo, fino a diventare clienti abituali. È qui che entra in gioco il potenziale della data science.
La data science trasforma i big data del marketing in insight azionabili, anche quando a prima vista sono meno intuitivi, ad esempio schemi comportamentali e co-occorrenze non evidenti. Di conseguenza, i marketer possono avere un quadro più chiaro del loro pubblico di riferimento, attirare nuovi clienti e fidelizzare quelli esistenti, ottimizzare le strategie di marketing, aumentare la visibilità dell’azienda, creare campagne pubblicitarie più efficaci, coinvolgere nuovi canali e, a loro volta, massimizzare in modo significativo i ricavi dell’azienda.
Uno dei casi d’uso più tipici della data science nel marketing è la previsione del churn rate dei clienti. Approfondiamo questo tema.
Caso d’uso di data science nel marketing: previsione del churn rate dei clienti
Il churn dei clienti è la tendenza dei clienti a cancellare l’abbonamento a un servizio che stavano utilizzando e, quindi, a smettere di essere clienti di quel servizio. Il churn rate è la percentuale di clienti persi in un intervallo di tempo predefinito. È l’opposto del tasso di crescita dei clienti, che traccia i nuovi ingressi.
Il churn rate è un indicatore molto importante della soddisfazione dei clienti e della salute complessiva del business. Oltre al churn naturale, che si verifica sempre in qualsiasi attività, o a quello stagionale tipico di alcuni servizi, ci sono altri fattori che possono indicare che qualcosa in azienda non funziona e va corretto. Questi fattori sono:
- assenza o bassa qualità del supporto clienti,
- esperienze negative dei clienti,
- passaggio a un competitor con condizioni o prezzi migliori,
- cambiamento delle priorità dei clienti,
- i clienti di lunga data non si sentono soddisfatti,
- il servizio non ha soddisfatto le aspettative dei clienti,
- problemi finanziari,
- protezione antifrode sui pagamenti dei clienti.
Un churn rate elevato rappresenta un serio problema per qualsiasi azienda per i seguenti motivi:
- È correlato a una perdita di ricavi per l’azienda.
- Costa molto di più acquisire nuovi clienti che mantenere quelli esistenti. Questo è particolarmente vero nei mercati altamente competitivi.
- Nel caso di abbandono dovuto a scarso servizio clienti, la reputazione dell’azienda può essere gravemente danneggiata dalle recensioni negative lasciate da ex clienti insoddisfatti sui social media o sui siti di recensioni.
La retention è una componente cruciale della strategia di business per tutti i servizi in abbonamento. Per prevedere il churn rate e adottare le relative misure preventive, è necessario raccogliere e analizzare le informazioni sul comportamento dei clienti (intervalli di acquisto, periodo complessivo di permanenza come cliente, cancellazioni, chiamate e messaggi di follow-up, attività online) e capire quali attributi e combinazioni sono caratteristici dei clienti a rischio di abbandono. Sapere in anticipo quali clienti potrebbero disdire a breve, soprattutto se ad alto valore o di lunga data, può aiutare l’azienda a concentrarsi proprio su di loro e a sviluppare una strategia efficace per convincerli a restare. L’approccio può includere una chiamata a questi clienti con un’offerta speciale di un regalo, uno sconto, un upgrade dell’abbonamento allo stesso prezzo o qualsiasi altra esperienza personalizzata.
Dal punto di vista tecnico, la previsione del churn è un tipico problema di classificazione di machine learning, in cui i clienti vengono etichettati come "sì" o "no" in termini di rischio di abbandono. Vediamo questo caso d’uso in Python su dati reali.
Modelleremo il churn nel settore telecom, dove i clienti possono avere più servizi con una società di telecomunicazioni sotto un unico contratto principale. Il dataset contiene le caratteristiche dell’attività dei clienti, ripulite, e un’etichetta di churn che indica se un cliente ha abbandonato o meno.
Diamo un’occhiata ai dati ed esploriamo la distribuzione del churn rate:
import pandas as pd
telcom = pd.read_csv('telco.csv')
print(f'Number of customers: {telcom.shape[0]:,}\n'
f'Churn values: {set(telcom['Churn'])}\n\n'
f'Churn distribution, %:\n{round(telcom.groupby(['Churn']).size()/telcom.shape[0]*100).convert_dtypes()}')
Number of customers: 7,032
Churn values: {0, 1}
Churn distribution, %:
Churn
0 73
1 27
dtype: float64
Il 27% dei clienti ha abbandonato, un tasso piuttosto elevato. Rispetto al precedente caso d’uso di data science, tuttavia, questo dataset non sembra presentare un grave problema di squilibrio tra classi.
Ora pre-processeremo i dati per applicare tecniche di machine learning e prevedere il churn. Questo include la suddivisione dei dati in set di training e test e l’estrazione delle variabili di input e di destinazione:
from sklearn.model_selection import train_test_split
target = ['Churn']
custid = ['customerID']
cols = [col for col in telcom.columns if col not in custid + target]
X = telcom[cols]
y = telcom[target]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
Il primo algoritmo di modellazione che useremo per prevedere le etichette di churn e stimare l’accuratezza dei risultati è un semplice modello di classificazione con regressione logistica:
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
lr = LogisticRegression()
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.8009
Poi aggiungiamo una funzionalità alla nostra regressione logistica, ovvero l’esecuzione su dati scalati con regolarizzazione L1 per effettuare la selezione delle caratteristiche insieme alla costruzione del modello. Valori diversi del parametro C (che è l’inverso dell’intensità della regolarizzazione) influiscono sull’accuratezza del modello. Per ora impostiamo C a 0,025:
lr = LogisticRegression(penalty='l1', C=0.025, solver='liblinear')
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.7969
Ora ottimizzeremo il parametro C per la regolarizzazione L1 per individuare il valore ottimale che riduce la complessità del modello mantenendo buone metriche prestazionali. A tal fine, itereremo su diversi valori di C, costruiremo istanze di regressione logistica per ciascuno e calcoleremo le metriche di performance.
La lista C è stata creata in anticipo con i possibili valori del parametro. L’array l1_metrics è stato costruito con 3 colonne: la prima con i valori di C, le successive due come segnaposto per il conteggio dei coefficienti non nulli e per l’accuracy del modello. Proviamo questo approccio:
C Non-Zero Coeffs Accuracy
0 1.0000 23.0 0.801479
1 0.5000 22.0 0.799204
2 0.2500 21.0 0.802048
3 0.1000 20.0 0.802617
4 0.0500 18.0 0.802048
5 0.0250 13.0 0.796928
6 0.0100 5.0 0.790102
7 0.0050 3.0 0.783276
8 0.0025 2.0 0.745734
Vediamo che valori di C più bassi riducono il numero di coefficienti diversi da zero (cioè le feature per la modellazione) diminuendo la complessità del modello, ma fanno anche calare l’accuratezza. Sembra che il valore di C pari a 0,05 sia quello ottimale: riduce il numero di feature a 18 e fornisce un’accuratezza leggermente superiore a quella del modello senza regolarizzazione.
Ora proviamo un altro algoritmo di modellazione: l’albero decisionale:
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
print(f'Test accuracy: {round(accuracy_score(y_test, predictions), 4)}')
Test accuracy: 0.7275
Per scegliere un modello più preciso evitando l’overfitting, possiamo provare a regolare la profondità dell’albero (parametro max_depth) e identificarne il valore ottimale. Tecnicamente, il processo è molto simile a quello usato sopra per selezionare il parametro C ottimale della regressione logistica: qui itereremo su più valori di max_depth, adatteremo un albero decisionale per ciascuno e calcoleremo le metriche di performance.
La lista depth_list è stata creata in anticipo con i possibili valori del parametro. L’array depth_tuning è stato costruito con 2 colonne: la prima contiene i candidati per la profondità e l’altra è un segnaposto per l’accuracy. Applichiamo questo approccio e troviamo la profondità ottimale:
depth_list = list(range(2, 15))
depth_tuning = np.zeros((len(depth_list), 2))
depth_tuning[:, 0] = depth_list
for index in range(len(depth_list)):
clf = DecisionTreeClassifier(max_depth=depth_list[index])
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
depth_tuning[index, 1] = accuracy_score(y_test, predictions)
col_names = ['Max_Depth', 'Accuracy']
print(pd.DataFrame(depth_tuning, columns=col_names))
Max_Depth Accuracy
0 2.0 0.756542
1 3.0 0.783276
2 4.0 0.782708
3 5.0 0.791809
4 6.0 0.778157
5 7.0 0.780432
6 8.0 0.757110
7 9.0 0.762230
8 10.0 0.763936
9 11.0 0.752560
10 12.0 0.745165
11 13.0 0.732651
12 14.0 0.727531
Quindi, l’accuracy inizialmente aumenta con l’aumentare della profondità per poi calare. Con max_depth pari a 5, l’albero mostra l’accuratezza più alta; possiamo quindi considerare questo valore come profondità ottimale.
Dopo aver identificato i migliori valori dei parametri per i modelli di regressione logistica e albero decisionale, ricostruiamo tali modelli e poi individuiamo e interpretiamo i principali fattori che fanno aumentare o diminuire il churn.
Per il modello di regressione logistica, estrarremo ed esploreremo gli esponenti dei coefficienti risultanti:
# Reconstructing the best model
lr = LogisticRegression(penalty='l1', C=0.05, solver='liblinear')
lr.fit(X_train, y_train)
predictions = lr.predict(X_test)
# Combining feature names and coefficients into one dataframe
feature_names = pd.DataFrame(X_train.columns, columns=['Feature'])
log_coef = pd.DataFrame(np.transpose(lr.coef_), columns=['Coefficient'])
coefficients = pd.concat([feature_names, log_coef], axis=1)
# Calculating exponents of the coefficients
coefficients['Exp_Coefficient'] = np.exp(coefficients['Coefficient'])
# Removing coefficients that are equal to zero
coefficients = coefficients[coefficients['Coefficient']!=0]
print(coefficients.sort_values(by=['Exp_Coefficient']))
Feature Coefficient Exp_Coefficient
21 tenure -0.907750 0.403431
4 PhoneService_Yes -0.820517 0.440204
17 Contract_Two year -0.595271 0.551413
8 TechSupport_Yes -0.418254 0.658195
16 Contract_One year -0.414158 0.660896
5 OnlineSecurity_Yes -0.412228 0.662173
6 OnlineBackup_Yes -0.143100 0.866667
3 Dependents_Yes -0.039299 0.961463
7 DeviceProtection_Yes -0.017465 0.982687
11 PaperlessBilling_Yes 0.071389 1.073999
1 SeniorCitizen_Yes 0.097904 1.102857
19 PaymentMethod_Electronic check 0.188533 1.207477
22 MonthlyCharges 0.901454 2.463182
Osserviamo che la caratteristica con l’effetto maggiore sulle probabilità di abbandono è la tenure. In generale, gli esponenti dei coefficienti inferiori a 1 riducono le probabilità, mentre quelli superiori a 1 le aumentano.
Per il modello ad albero decisionale, estrarremo e tracceremo le regole if-else:
# Reconstructing the best model
clf = DecisionTreeClassifier(max_depth=5)
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
from sklearn import tree
import graphviz
# Exporting a graphviz object from the trained decision tree
exported = tree.export_graphviz(decision_tree=clf,
out_file=None,
feature_names=cols,
precision=1,
class_names=['Not churn', 'Churn'],
filled=True)
graph = graphviz.Source(exported)
display(graph)

Abbiamo ottenuto una visualizzazione dell’albero decisionale ben leggibile, interpretabile come un insieme di regole if-else a partire dall’alto. Anche qui vediamo che la tenure del cliente è la variabile più importante che guida il churn. L’albero può essere costruito con più livelli, offrendo così ulteriori insight su altre variabili.
Come possibili passi successivi, possiamo continuare a regolare i parametri del modello, usare diversi approcci di suddivisione train/test, applicare e confrontare altri algoritmi di machine learning e analizzare varie tipologie di metriche per stimare le performance del modello.
Se vuoi approfondire la previsione del churn rate e altre applicazioni della data science nel marketing, questo corso su Machine Learning for Marketing in Python può essere un buon punto di partenza.

