
Caso studio: marketing data science end-to-end
Progetto pratico: predire il churn e costruire una strategia data-driven di retention.
Cosa imparerai
- Comprendere il problema analitico e il contesto decisionale
- Applicare esempi, metriche e controlli a casi reali
Collegamenti
import schedule
Caso studio: marketing data science end-to-end
Questo è un Lab, quindi il punto non è accumulare definizioni ma seguire un progetto dall’inizio alla fine e vedere quale decisione cambia a ogni passaggio. Lavoriamo su un ecommerce che ha dati transazionali, campagne attive e segnali di churn, e che vuole usare la data science per aumentare il valore cliente senza sprecare budget.
Il problema reale
Un ecommerce ha già tutto quello che serve: transazioni, campagne, segnali di abbandono e una richiesta chiara dal business. Il rischio non è la mancanza di dati, è costruire modelli separati che non arrivano mai a una decisione. Il caso end-to-end mette insieme feature, modello, valutazione e azione in un’unica catena, così ogni numero prodotto porta a una scelta concreta su dove intervenire.
Il problema vero non è quindi conoscere la materia in astratto. È decidere cosa fare quando i dati sono incompleti, le metriche ambigue o i vincoli operativi rendono fragile la lettura. Una buona analisi separa il segnale dal rumore, dichiara la baseline e indica quale azione diventa più difendibile.
Come impostare il ragionamento
Usa questa sequenza come mappa di lavoro. Ogni passaggio deve rendere più chiaro il costo di una decisione sbagliata, non aggiungere terminologia.
| Passaggio | Domanda da fare | Output atteso |
|---|---|---|
| Decisione | Che cosa cambia se capiamo meglio il fenomeno? | Scelta esplicita |
| Segnale | Quale dato osservabile riduce l’incertezza? | Metrica o evento |
| Baseline | Rispetto a cosa interpretiamo il risultato? | Confronto credibile |
| Vincolo | Che cosa può falsare la lettura? | Assunzione da dichiarare |
| Azione | Quale passo operativo segue? | Raccomandazione controllabile |
La stessa logica vale anche quando il budget consente di trattare solo una parte della base clienti. Se il modello assegna score di propensione ma puoi agire solo sul 15% degli utenti, la domanda diventa concreta: quale soglia massimizza il valore netto, quali clienti escludi e come dimostri che l’attivazione supera una regola semplice?
Come formalizzare il problema
Formalizzare non serve a complicare. Serve a rendere visibili le assunzioni, così un altro analista può riprodurre la logica, criticarla e arrivare alla stessa decisione partendo dagli stessi dati.
| Elemento | Definizione operativa | Controllo minimo |
|---|---|---|
| Unità di analisi | Oggetto su cui misuri il fenomeno | Utente, account, evento, ordine o periodo |
| Variabile osservata | Segnale che rappresenta il comportamento | Definizione stabile e tracciabile |
| Baseline | Stato contro cui confronti il segnale | Periodo, segmento, controllo o benchmark |
| Soglia decisionale | Punto in cui cambia l’azione | Criterio scritto prima della lettura |
| Rischio residuo | Errore che può restare anche dopo l’analisi | Sensitivity check o revisione qualitativa |
Il rischio principale, in questo tipo di lavoro, è scambiare un numero disponibile per una prova sufficiente.
Fase 1: feature engineering (settimana 1)
Si parte costruendo 20 feature da dati transazionali, navigazione, supporto e marketing. L’obiettivo è leggere il caso come una consegna di lavoro completa: ogni feature deve spiegare quale comportamento cattura e quale segnale di rischio porta con sé.
# Feature da dati transazionali
df['recency_days'] = (df['today'] - df['last_order_date']).dt.days
df['frequency_total'] = df.groupby('customer_id')['order_id'].transform('count')
df['monetary_total'] = df.groupby('customer_id')['amount'].transform('sum')
df['aov'] = df['monetary_total'] / df['frequency_total']
# Trend di utilizzo
df['active_days_last_14'] = df.groupby('customer_id')['active_day'].transform(
lambda x: x.rolling(14).sum())
df['active_days_prev_14'] = df.groupby('customer_id')['active_day'].transform(
lambda x: x.shift(14).rolling(14).sum())
df['usage_trend'] = df['active_days_last_14'] / df['active_days_prev_14'].clip(1)
# Segnali di attrito
df['has_payment_failure'] = (df['failed_payments_30d'] > 0).astype(int)
df['support_tickets_30d'] = df['support_tickets_30d']
df['avg_session_minutes_trend'] = df['avg_session_7d'] / df['avg_session_prev_7d'].clip(1)
# Engagement depth
features_list = ['feature_try_on', 'feature_style_quiz', 'feature_wishlist',
'feature_reviews', 'feature_referral']
df['engagement_depth'] = df[features_list].sum(axis=1)
# Segnali temporali
df['tenure_months'] = (df['today'] - df['signup_date']).dt.days / 30
df['is_month_1'] = (df['tenure_months'] <= 1).astype(int)
Fase 2: modello predittivo (settimana 2)
Con le feature pronte, addestriamo un Gradient Boosting per stimare la probabilità di churn nel mese successivo. Definiamo il churn come l’assenza di ordini nei 30 giorni seguenti e teniamo d’occhio quali feature pesano di più nella decisione del modello.
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import roc_auc_score, classification_report
feature_cols = ['recency_days', 'frequency_total', 'monetary_total', 'aov',
'usage_trend', 'has_payment_failure', 'support_tickets_30d',
'avg_session_minutes_trend', 'engagement_depth', 'tenure_months',
'is_month_1', 'days_since_last_login', 'email_open_rate_30d']
X = df[feature_cols].fillna(0)
y = df['churned_next_month'] # definizione: nessun ordine nei 30gg successivi
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y)
model = GradientBoostingClassifier(
n_estimators=200, max_depth=4, learning_rate=0.05, random_state=42)
model.fit(X_train, y_train)
probs = model.predict_proba(X_test)[:, 1]
auc = roc_auc_score(y_test, probs)
print(f"AUC: {auc:.3f}") # Target: >0.82
# Feature importance
importances = pd.Series(model.feature_importances_, index=feature_cols)
print(importances.sort_values(ascending=False).head(10))
Risultato atteso: AUC intorno a 0.84, con recency_days, usage_trend e tenure_months tra le tre feature più importanti.
Fase 3: segmentazione per azione (settimana 3)
Un buon punteggio di rischio non basta. Dividi i clienti in quattro quadranti incrociando Churn Risk (asse X) e Customer Value (asse Y), perché la stessa probabilità di abbandono richiede risposte diverse a seconda del valore del cliente.
df['churn_risk'] = model.predict_proba(df[feature_cols].fillna(0))[:, 1]
df['risk_tier'] = pd.qcut(df['churn_risk'], 4, labels=['low','medium','high','critical'])
df['value_tier'] = pd.qcut(df['monetary_total'], 4, labels=['low','medium','high','vip'])
segments = df.groupby(['risk_tier', 'value_tier']).agg(
customers=('customer_id', 'count'),
avg_ltv=('monetary_total', 'mean')
).reset_index()
A ogni quadrante corrisponde un’azione, un canale e un budget stimato.
| Rischio × Valore | Segmento | Azione | Canale | Budget stimato |
|---|---|---|---|---|
| Critical × VIP | ”Save our stars” | Call personale del customer success entro 24h | Telefono, email dedicata | €50-100/cliente |
| Critical × Low | ”Auto-save” | Sequenza email automatica con offerta | Email, push | €5-10/cliente |
| High × VIP | ”Proactive love” | Invito esclusivo, sneak peek nuove collezioni | Email, direct mail | €20-30/cliente |
| Low × VIP | ”Loyalty reward” | Programma referral, accesso anticipato saldi | Email, in-app | €10-15/cliente |
| Low/Medium × Low | ”Nurture” | Contenuti educativi, social proof | Email, in-app | €2-5/cliente |
Fase 4: deploy e monitoring (settimana 4)
Il modello vive solo se entra in un flusso quotidiano e se qualcuno si accorge quando smette di funzionare. La pipeline assegna gli score ogni mattina e un controllo mensile verifica che l’AUC non scenda sotto la soglia di degrado.
# Pipeline di scoring giornaliera
def daily_churn_scoring():
new_data = extract_features_from_warehouse()
new_data['churn_risk'] = model.predict_proba(new_data[feature_cols])[:, 1]
write_to_activation_table(new_data[['customer_id', 'churn_risk', 'risk_tier']])
schedule.every().day.at("06:00").do(daily_churn_scoring)
# Monitoring AUC drift mensile
def check_auc_drift():
recent_actuals = get_recent_outcomes()
recent_preds = model.predict_proba(recent_actuals[feature_cols])[:, 1]
current_auc = roc_auc_score(recent_actuals['churned'], recent_preds)
if current_auc < 0.78: # soglia di degrado
send_alert(f"AUC drift detected: {current_auc:.3f}")
La tabella mrt_activation__customer_health viene sincronizzata via Reverse ETL su Braze e Salesforce. I customer success manager vedono la lista “Save our stars” direttamente nel CRM.
Fase 5: presentazione al CEO (2 slide)
La prima slide dimostra che il modello funziona. L’AUC di 0.84 significa che nell’84% dei casi una coppia (churner, non-churner) viene ordinata correttamente. Prendendo il 20% più a rischio catturiamo il 64% dei churner reali, e nel segmento “Critical” la precision è del 71%: chi predici come critical churna davvero nel 71% dei casi.
La seconda slide traduce tutto in valore. La popolazione “Critical × VIP” conta 1.800 clienti con LTV medio di €2.400. Salvandone il 40% con intervento proattivo si preservano 720 clienti per €2.400, cioè €1.73M di LTV. Il costo del programma è di €180K all’anno, tra un FTE di customer success e i tool, per un ROI di 9.6x nel primo anno.
Lab ed esercizi
La consegna minima include almeno 15 feature ingegnerizzate con documentazione, un modello con AUC superiore a 0.80 e precision@20% sopra 0.60, i quattro quadranti con azioni, canali e budget associati, una pipeline di scoring giornaliera funzionante, il monitoring dell’AUC drift configurato e una presentazione per il CEO con l’impatto stimato in euro.
Se vuoi partire più in piccolo, comincia da una scheda di una pagina: decisione da supportare, metrica primaria, baseline, rischio principale e azione se il segnale è confermato. Al livello intermedio costruisci una tabella con tre segmenti o scenari, indicando per ciascuno cosa cambia, quale spiegazione alternativa è plausibile e quale controllo useresti prima di raccomandare un’azione. Al livello research-grade prepara un decision memo completo: ipotesi, dati richiesti, criteri di esclusione, controlli di qualità, soglia decisionale, rischio residuo e piano di monitoraggio. Se non hai dati reali, crea un dataset sintetico con almeno 200 righe, una dimensione temporale, una dimensione segmento e una metrica di outcome.
Controllo di qualità
Prima di usare questo lavoro in una decisione, controlla sempre completezza, duplicati, timezone, definizioni cambiate e segmenti esclusi. Molte analisi apparentemente sofisticate falliscono perché il dato di partenza misura un comportamento diverso da quello che il team crede di osservare.
L’errore più comune è usare il caso come etichetta invece che come processo: un grafico senza decisione, una metrica senza baseline, una conclusione senza l’assunzione che potrebbe invalidarla. La domanda di controllo è semplice: se questo risultato fosse instabile, quale scelta sbaglierei? Se la risposta non è concreta, manca ancora il collegamento tra analisi e azione.
Quiz e checkpoint
Per verificare di aver chiuso il cerchio, rispondi a queste cinque domande. Quale decisione concreta dovrebbe migliorare il lavoro? Quale unità di analisi rende il problema misurabile? Quale baseline useresti per evitare una lettura isolata? Quale assunzione, se falsa, cambierebbe la conclusione? E quale controllo presenteresti a uno stakeholder non tecnico prima di raccomandare un’azione?
Riepilogo
Il caso end-to-end diventa utile quando produce una decisione più chiara, non quando aggiunge terminologia. La catena è sempre la stessa: feature, modello, valutazione, segmentazione, azione e monitoraggio, con baseline e rischio dichiarati a ogni passo. Hai assimilato il metodo quando riesci a spiegarlo senza gergo, applicarlo a un caso piccolo ma realistico e difendere una raccomandazione includendo i limiti e i prossimi controlli. Categoria Lab, difficoltà advanced, tempo stimato 28 minuti.
Percorso collegato
Lezioni da leggere insieme
Questi collegamenti portano la lezione dentro il resto del corso: basi da riprendere, passaggi successivi e connessioni tematiche tra moduli.