Segmentare la customer base con RFM

RFM Segments

Segmentare la customer base può servire tra le altre cose a: personalizzare i programmi di marketing e le campagne con una comunicazione e proposta di valore ad hoc per ogni segmento, previsione dei movimenti tra i segmenti, previsione del Customer Lifetime Value.

Come si procede in pratica? Di seguito mostro come ho segmentato la customer base di un e-commerce usando l’approccio RFM (Recency, Frequency, Monetary Value) e Python come tool per la gestione/elaborazione dei dati. Il dataset contiene i dati reali dal 2016 al 2018 compresi di vendite online (con gli ID dei clienti anonimizzati). Questi gli step che ho seguito:

  1. Definizione dei segmenti e metodo di segmentazione
  2. Caricamento, pulizia e trasformazione dei dati
  3. Segmentazione: associare ogni cliente a un segmento
  4. Visualizzazione e utilizzo della segmentazione

Ho usato Python per il caricamento e le operazioni di trasformazione ed elaborazione con l’idea di avere uno strumento facilmente scalabile anche su dataset da milioni di record. In alternativa è possibile utilizzare qualsiasi linguaggio orientato all’elaborazione dei dati, ad esempio R, oppure una combinazione di SQL+Excel, etc.

Definizione dei segmenti e metodo di segmentazione

RFM è utilizzato da anni nel Retail, e-Commerce, Telco, Media come metodo di segmentazione behavior-based. I segmenti possono essere costruiti a partire dalle informazioni contenute nei database degli ordini/vendite. Il costo computazionale per l’elaborazione di RFM è relativamente basso, specie se comparato con approcci più orientati al data mining/statistica come k-means o clustering, e può quindi essere utilizzato anche su dataset da milioni di record. Data la praticità e possibilità di utilizzo in un’ampia varietà di contesti, userò quindi RFM come metodologia di segmentazione, riservandomi di sostituire il classico scoring numerico con veri e propri segmenti significativi dal punto di vista manageriale.

Gli ordini e la Customer Base analizzati sono quelli dell’e-commerce Olist Store per il periodo 2016-2018, nel dataset pubblicamente condiviso su Kaggle . Questo lo schema del DB esportato in forma di flat file:

Definizione dei Segmenti

RFM utilizza tre variabili: Recency (distanza temporale dell’acquisto), Frequency (frequenza) e Value (valore monetario della transazione) per segmentare la customer base. Ogni business può però decidere come raggruppare i clienti -a partire dalle tre variabili- in base alle proprie logiche di business. In questo caso ho deciso di segmentare come segue:

  • Inactive – clienti che non hanno ordinato negli ultimi due anni
  • Cold – nessun ordine nell’ultimo anno, almeno un ordine negli ultimi due anni
  • Warm – clienti con l’ultimo acquisto effettuato tra sei e dodici mesi dalla data di analisi
  • Active Hi Value – almeno un acquisto negli ultimi sei mesi, valore medio dell’ordine superiore a quello medio complessivo, più di un ordine in totale
  • Active Low Value – almeno un acquisto negli ultimi sei mesi, valore medio dell’ordine inferiore a quello medio complessivo, più di un ordine in totale
  • New – primo e unico ordine effettuato negli ultimi sei mesi

Caricamento dati e elaborazioni

Le informazioni minime necessarie sono:

  • Customer ID
  • Data ordine
  • Ordine/Numero ordini fatti
  • Valore ordine (o valore medio ordini)

Il nostro dataset non fornisce direttamente le informazioni richieste, sono necessarie alcune operazioni di pulizia e aggregazione. La prima operazione, dopo il caricamento, è la pulizia della tabella ordini con la rimozione dei record in stato “canceled”. E’ poi necessario fare una join tra le tabelle ordini e clienti:

#join (merge)  the two datasets
tbl_order = pd.merge(order_items, orders_customer[['order_id','customer_id', 'order_purchase_timestamp']],
                     how ='inner', on ='order_id') 

tbl_order = tbl_order[['order_id', 'customer_id','order_purchase_timestamp', 'price','freight_value']]

La Recency va ora calcolata come numero di giorni trascorsi dalla data ordine a quella di analisi. Il dataset fornito ha l’ultimo ordine datato ottobre 2018, ho quindi fissato la baseline per l’analisi al 31 ottobre 2018. E’ così possibile calcolare la tabella (in Python: dataframe ) RFM:

# Computing RFM indicators
rfm = tbl_order.groupby('customer_id').aggregate(
        {'customer_id': 'min','days_passed': ['min', 'max', 'count'], 'total_amount': ['mean','sum'] 
                             })
rfm.columns = ['customer_id', 'recency','first_purchase', 'frequency','avg_amount', 'tot_purchases']

Segmentazione – assegnare i singoli clienti ai segmenti

RFM Segments

Siamo ora pronti per tradurre le nostre logiche di segmentazione in codice Python:

# segmentation
avg_purchase=rfm['avg_amount'].mean()
rfm['segment'] = np.nan 
rfm.loc[rfm['recency']>365*2, 'segment']= 'inactive'
rfm.loc[(rfm['recency']<=365*2) & (rfm['recency']>365), 'segment'] = 'cold'
rfm.loc[(rfm['recency']<=365) & (rfm['recency']>365/2), 'segment'] = 'warm'
rfm.loc[(rfm['recency']<=365/2) & (rfm['tot_purchases']>=avg_purchase), 'segment'] = 'active hi value'
rfm.loc[(rfm['recency']<=365/2) & (rfm['tot_purchases']<avg_purchase), 'segment'] = 'active low value'
#OVERWRITE SOME OF THE PREVIOUS 'ACTIVE LOW/HI VALUE"
rfm.loc[(rfm['recency']<=365/2) & (rfm['frequency']==1), 'segment'] = 'new'

Visualizzare i dati e agire

Ora che la segmentazione è completata possiamo:

  • Monitora la composizione e la mobilità dei segmenti nel tempo (esempio un incremento sulla percentuale di clienti inattivi, ecc.)  
  • personalizza la comunicazione e l’offerta segmento per segmento, ad esempio campagne win-back rivolte a clienti “inattivi”, welcome series per il segmento “nuovo”, ecc.
  • controllare e monitorare le response rate segmento per segmento
  • rieseguire la segmentazione almeno mensilmente
  • utilizzare i segmenti per analisi previsionali sul Churn, sulla mobilità tra segmenti, sul CLV Custmer Lifetime Value. Scriverò nelle prossime settimane un nuovo post sull’uso del Machine Learning per sviluppare questo tipo di previsioni.