Previsione del lifetime value cliente con AI Platform: addestramento dei modelli

Questo articolo è la seconda parte di una serie in quattro parti che illustra come è possibile prevedere il lifetime value cliente (CLV) utilizzando AI Platform (AI Platform) su Google Cloud.

Gli articoli di questa serie includono:

  • Parte 1 - Introduzione. Introduce il CLV e due tecniche di modellazione per prevedere il CLV.
  • Parte 2: addestramento del modello (questo articolo). Illustra come preparare i dati e addestrare i modelli.
  • Parte 3 - Deployment in produzione. Descrive come eseguire il deployment dei modelli illustrati nella Parte 2 in un sistema di produzione.
  • Parte 4 - Utilizzo di AutoML Tables. Mostra come utilizzare AutoML Tables per creare un modello ed eseguirne il deployment.

Il codice per l'implementazione di questo sistema si trova in un repository GitHub. Questa serie illustra l'utilizzo del codice e il modo in cui viene utilizzato.

Introduzione

Questo articolo segue la Parte 1, in cui vengono descritti due diversi modelli per prevedere il lifetime value cliente (CLV):

  • Modelli provocatori
  • Modelli di rete neurale profonda (DNN), un tipo di machine learning

Come indicato nella Parte 1, uno degli obiettivi di questa serie è confrontare questi modelli per la previsione del CLV. Questa parte della serie descrive come preparare i dati e creare e addestrare entrambi i tipi di modello per prevedere il CLV e fornisce alcune informazioni di confronto.

Installare il codice

Se vuoi seguire la procedura descritta in questo articolo, devi installare il codice campione da GitHub.

  1. Se hai installato gcloud CLI, apri una finestra del terminale sul computer per eseguire questi comandi. Se non hai installato l'interfaccia a riga di comando gcloud, apri un'istanza di Cloud Shell.

    VAI A Cloud Shell

  2. Clona il repository del codice campione:

    git clone
    https://github.com/GoogleCloudPlatform/tensorflow-lifetime-value
    
  3. Per configurare l'ambiente, segui le istruzioni per l'installazione nella sezione Installa del file README.

Preparazione dei dati

In questa sezione viene descritto come recuperare e cancellare i dati.

Recupero e pulizia del set di dati di origine

Prima di poter calcolare il CLV, devi assicurarti che i dati di origine contengano almeno quanto segue:

  • Un ID cliente utilizzato per differenziare singoli clienti.
  • Un importo di acquisto per cliente che mostra l'importo speso da un cliente in un momento specifico.
  • Una data per ogni acquisto.

In questo articolo parleremo di come addestrare i modelli utilizzando i dati sulle vendite storiche tratte dal set di dati sulla vendita al dettaglio online disponibile presso il Repository di machine learning UCI.[1]

Il primo passaggio consiste nel copiare il set di dati come file CSV in Cloud Storage. Utilizzando uno degli strumenti di caricamento per BigQuery, puoi creare una tabella denominata data_source. Questo nome è arbitrario, ma il codice nel repository GitHub utilizza questo nome. Il set di dati è disponibile in un bucket pubblico associato a questa serie ed è già stato convertito in formato CSV.

  1. Sul tuo computer o in Cloud Shell, esegui i comandi documentati nella sezione Configurazione del file README nel repository GitHub.

Il set di dati di esempio contiene i campi elencati nella tabella seguente. Per l'approccio descritto in questo articolo, utilizzi solo i campi in cui la colonna usato è impostata su . Alcuni campi non vengono utilizzati direttamente, ma contribuiscono a creare nuovi campi, ad esempio UnitPrice e Quantity, order_value.

Risorse utilizzate Campo Tipo Descrizione
No InvoiceNo STRING Nominale. Un numero integrale di sei cifre assegnato in modo univoco a ogni transazione. Se questo codice inizia con la lettera c, indica un annullamento.
No StockCode STRING Codice prodotto (articolo). Nominale, un numero integrale di cinque cifre assegnato in modo univoco a ciascun prodotto.
No Description STRING Nome del prodotto (articolo). Nominale.
Quantity INTEGER Le quantità di ciascun prodotto (articolo) per transazione. Numerico.
InvoiceDate STRING Data e ora della fattura nel formato mm/gg/aa hh:mm. Il giorno e l'ora in cui è stata generata ogni transazione.
UnitPrice FLOAT Prezzo unitario. Numerico. Il prezzo del prodotto per unità in sterline.
CustomerID STRING Numero cliente. Nominale. Un numero integrale di cinque cifre assegnato in modo univoco a ciascun cliente.
No Country STRING Nome del paese. Nominale. Il nome del paese in cui risiede ogni cliente.

Pulizia dei dati

Indipendentemente dal modello utilizzato, devi eseguire una serie di passaggi di preparazione e pulizia comuni a tutti i modelli. Le operazioni che seguono sono necessarie per ottenere un insieme di campi utilizzabili e di record:

  1. Raggruppa gli ordini in base al giorno invece di usare InvoiceNo, perché l'unità di tempo minima utilizzata dai modelli probabilistici in questa soluzione è un giorno.
  2. Conserva solo i campi utili per i modelli probabilistici.
  3. Conserva solo i record che hanno quantità positive dell'ordine e valori monetari, come gli acquisti.
  4. Conserva solo i record con quantità negative dell'ordine, come i resi.
  5. Conserva solo i record con un ID cliente.
  6. Conserva solo i clienti che hanno effettuato un acquisto negli ultimi 90 giorni.
  7. Conserva solo i clienti che hanno effettuato acquisti due volte nel periodo di tempo utilizzato per creare le funzionalità.

Puoi eseguire tutte queste operazioni usando la seguente query BigQuery. Come con i comandi precedenti, esegui questo codice ovunque tu abbia clonato il repository GitHub. Poiché i dati sono vecchi, la data 12 dicembre 2011 viene considerata come la data di oggi ai fini dell'articolo.

WHERE
  -- Bought in the past 3 months
  DATE_DIFF(DATE('{{ dag_run.conf['predict_end'] }}'), latest_order, DAY) <= 90
  -- Make sure returns are consistent.
  AND (
    (order_qty_articles > 0 and order_Value > 0) OR
    (order_qty_articles < 0 and order_Value < 0)
  )

Questa query esegue due attività. Innanzitutto, se il set di dati funzionante è di grandi dimensioni, la query riduce questo valore. Il set di dati funzionante per questa soluzione è piuttosto piccolo, ma questa query può ridurre un set di dati estremamente grande di due ordini di grandezza in pochi secondi.

In secondo luogo, la query crea un set di dati di base su cui lavorare come simile alla seguente:

customer_id order_date order_value order_qty_articles
16915 2011-08-04 173,7 6
15349 2011-07-04 107,7 77
14794 2011-03-30 -33,9 -2

Il set di dati cancellato contiene anche il campo order_qty_articles. Questo campo è incluso solo per l'utilizzo da parte della rete neurale profonda (DNN) descritta nella sezione successiva.

Definizione degli intervalli di addestramento e target

Per prepararti all'addestramento dei modelli, devi scegliere una data di soglia. Tale data separa gli ordini in due partizioni:

  • Gli ordini antecedenti alla data di soglia vengono utilizzati per addestrare il modello.
  • Gli ordini successivi alla data di soglia vengono utilizzati per calcolare il valore target.

Cronologia vendite per 4 clienti che mostrano una data soglia

La libreria Lifetime include metodi per la pre-elaborazione dei dati. Tuttavia, i set di dati utilizzati per il CLV possono essere abbastanza grandi, il che rende poco pratico l'esecuzione del pre-elaborazione dei dati su una singola macchina. L'approccio descritto in questo articolo utilizza query che vengono eseguite direttamente in BigQuery per suddividere gli ordini in due set. I modelli ML e probabilità utilizzano le stesse query, assicurando che entrambi i modelli funzionino sugli stessi dati.

La data ottimale della soglia potrebbe variare per i modelli di ML e per i modelli probabilistici. Puoi aggiornare questo valore di data direttamente nell'istruzione SQL. Considera la data ottimale per la soglia come un iperparametro. Trova il valore più appropriato esplorando i dati ed eseguendo alcuni addestramenti di test.

La data di soglia viene utilizzata nella clausola WHERE della query SQL che seleziona i dati di addestramento dalla tabella dei dati eliminati, come mostrato nell'esempio seguente:

order_date <= DATE('{{ dag_run.conf['threshold_date'] }}')

Aggregazione dei dati

Dopo aver suddiviso i dati in intervalli di addestramento e di destinazione, puoi aggregarli per creare funzionalità e target effettivi per ogni cliente. Per i modelli probabilistici, l'aggregazione è limitata ai campi attualità, frequenza e valore monetario (RFM). Per i modelli DNN, i modelli utilizzano anche funzionalità RFM, ma possono utilizzare funzionalità aggiuntive per effettuare previsioni migliori.

La seguente query mostra come creare contemporaneamente modelli di DNN e di modelli probabilistici:

tf.monetary_dnn,
tf.monetary_btyd,
tf.cnt_orders AS frequency_dnn,
tf.cnt_orders - 1 AS frequency_btyd,
tf.recency,
tf.T,
ROUND(tf.recency/cnt_orders, 2) AS time_between,
ROUND(tf.avg_basket_value, 2) AS avg_basket_value,
ROUND(tf.avg_basket_size, 2) AS avg_basket_size,
tf.cnt_returns,
(CASE
    WHEN tf.cnt_returns > 0 THEN 1
    ELSE 0 END) AS has_returned,

-- Used by BTYD mainly, potentially DNN if clipped improve results
(CASE
    WHEN tf.cnt_orders - 1 > 600 THEN 600
    ELSE tf.cnt_orders - 1 END) AS frequency_btyd_clipped,
(CASE
    WHEN tf.monetary_btyd > 100000 THEN 100000
    ELSE ROUND(tf.monetary_btyd, 2) END) AS monetary_btyd_clipped,
(CASE
    WHEN tt.target_monetary > 100000 THEN 100000
    ELSE ROUND(tt.target_monetary, 2) END) AS target_monetary_clipped,

-- Target calculated for overall period
ROUND(tt.target_monetary, 2) as target_monetary

La tabella seguente elenca le funzionalità create dalla query.

Nome funzionalità Descrizione Probabilistico DNN
monetary_dnn La somma di tutti i valori monetari per cliente durante il periodo delle funzionalità. x
monetary_btyd La media di tutti i valori monetari di tutti gli ordini per ogni cliente durante il periodo della funzionalità. I modelli probabilistici presuppongono che il valore del primo ordine sia 0. La query viene applicata dalla query. x
recency Il periodo di tempo che intercorre tra il primo e l'ultimo ordine effettuato da un cliente durante il periodo della funzionalità. x
frequency_dnn Il numero di ordini effettuati da un cliente durante il periodo della funzionalità. x
frequency_btyd Il numero di ordini effettuati da un cliente durante il periodo delle funzionalità meno il primo. x
T Il tempo che intercorre tra il primo ordine effettuato da un cliente e la fine del periodo delle funzionalità. x x
time_between Il tempo medio tra gli ordini per un cliente durante il periodo delle funzionalità. x
avg_basket_value Il valore monetario medio del carrello del cliente durante il periodo delle funzionalità. x
avg_basket_size Il numero di articoli che il cliente ha in media nel carrello durante il periodo delle funzionalità. x
cnt_returns Il numero di ordini restituiti dal cliente durante il periodo della funzionalità. x
has_returned Se il cliente ha restituito almeno un ordine durante il periodo di funzionalità. x
frequency_btyd_clipped Uguale a frequency_btyd, ma con clip di valori anomali. x
monetary_btyd_clipped Uguale a monetary_btyd, ma con clip di valori anomali. x
target_monetary_clipped Uguale a target_monetary, ma con clip di valori anomali. x
target_monetary L'importo totale speso da un cliente, inclusi i periodi di addestramento e di destinazione. x

La selezione di queste colonne viene eseguita nel codice. Per i modelli probabilistici, la selezione viene effettuata mediante un DataFrame Pandas:

df_ft = pd.read_csv(ft_file)

# Extracts relevant dataframes for RFM:
# - summary has aggregated values before the threshold date
# - actual_df has values of the overall period.
summary = df_ft[['customer_id', 'frequency_btyd', 'recency', 'T',
                 'monetary_btyd']]

Per i modelli DNN, le funzionalità di TensorFlow sono definite nel file context.py. Per questi modelli, quanto segue viene ignorato come funzionalità:

  • customer_id. Si tratta di un valore univoco che non è utile come funzionalità.
  • target_monetary. Questo è il target che il modello deve prevedere e, pertanto, non viene utilizzato come input.

Creazione dei set di addestramento, valutazione e test per DNN

Questa sezione si applica solo ai modelli DNN. Per addestrare un modello ML, devi utilizzare tre set di dati non sovrapposti:

  • Il set di dati di addestramento (70-80%) viene utilizzato per apprendere le ponderazioni in modo da ridurre una funzione di perdita. L'addestramento continua fino a quando la funzione di perdita non rifiuta più.

  • Il set di dati di valutazione (10-15%) viene utilizzato durante la fase di addestramento per evitare l'overfitting, ovvero quando un modello ha un buon rendimento sui dati di addestramento, ma non generalizza bene.

  • Il set di dati test (10-15%) deve essere utilizzato solo una volta, dopo aver completato tutta la formazione e la valutazione, per eseguire una misurazione finale delle prestazioni del modello. Questo set di dati non è mai stato registrato dal modello durante il processo di addestramento, pertanto fornisce una misurazione statisticamente valida dell'accuratezza del modello.

La query seguente crea un set di addestramento con circa il 70% dei dati. La query separa i dati utilizzando la seguente tecnica:

  • Viene calcolato un hash dell'ID cliente che produce un numero intero.
  • Un'operazione di modulo viene utilizzata per selezionare i valori hash inferiori a una determinata soglia.
SELECT
  *
FROM
  `{{ dag_run.conf['project'] }}.{{ dag_run.conf['dataset'] }}.features_n_target`
WHERE
  -- TRAIN
  MOD(ABS(FARM_FINGERPRINT(CAST(customer_id AS STRING))), 100000) <= 70000

Lo stesso concetto viene utilizzato per il set di valutazione e i set di test, in cui vengono conservati i dati che superano la soglia.

Formazione

Come hai visto nella sezione precedente, puoi utilizzare diversi modelli per cercare di prevedere il CLV. Il codice utilizzato in questo articolo è stato progettato per consentirti di decidere quale modello utilizzare. Scegli il modello utilizzando il parametro model_type che trasmetti al seguente script shell di addestramento. Il codice si occupa di tutto il resto.

estimator = get_estimator(estimator_name=args.model_type,
                          config=config,
                          params=params,
                          model_dir=model_dir)

Il primo obiettivo dell'addestramento è che entrambi i modelli siano in grado di superare un ingenuo benchmark, che chiamiamo di seguito. Se entrambi i tipi di modelli riescono a superare questa condizione (e dovrebbero farlo), puoi confrontare il rendimento di ogni tipo con l'altro.

Benchmarking dei modelli

Ai fini di questa serie, viene definito un benchmark innovativo utilizzando i seguenti parametri:

  • Valore medio del carrello. Questo valore viene calcolato in tutti gli ordini effettuati prima della data di soglia.
  • Conteggio ordini. Questo valore viene calcolato per l'intervallo di addestramento su tutti gli ordini effettuati prima della data della soglia.
  • Moltiplicatore di numeri. Questo valore viene calcolato in base al rapporto tra il numero di giorni precedenti alla data della soglia e il numero di giorni compresi tra la data corrente e quella corrente.

Il benchmark presuppone per errore che il tasso di acquisti stabilito da un cliente durante l'intervallo di addestramento rimanga costante nell'intervallo target. Quindi, se un cliente ha acquistato 6 volte in 40 giorni, si presume che acquistano 9 volte in 60 giorni (60/40 * 6 = 9). Moltiplicando il moltiplicatore di conteggi, il conteggio degli ordini e il valore medio del carrello per ciascun cliente ottieni un valore target previsto ingenuo per quel cliente.

L'errore di benchmark è l'errore quadrato medio (RMSE) radice: la media tra tutti i clienti della differenza assoluta tra il valore target previsto e il valore target effettivo. Il RMSE viene calcolato utilizzando la seguente query in BigQuery:

SELECT
  ROUND(SQRT( SUM(POW(predicted_monetary - target_monetary, 2)) / COUNT(1) ), 2) as rmse
FROM (
  SELECT
    tf.customer_id,
    avg_basket_value * ( cnt_orders * (1 + target_days/feature_days) ) AS predicted_monetary,
    ROUND(tt.target_monetary, 2) AS target_monetary

Il benchmark restituisce un RMSE di 3760, come mostrato nei risultati seguenti dell'esecuzione del benchmark. I modelli devono battere questo valore.

Risultati benchmark

Modelli provocatori

Come menzionato nella Parte 1 di questa serie, questa serie utilizza una libreria Python denominata Lifetime che supporta vari modelli, tra cui i modelli BD/NBD di Pareto e la distribuzione binomiale negativa (NBD). Il codice di esempio riportato di seguito mostra come utilizzare la libreria Lifetime per eseguire previsioni del lifetime value con modelli probabilistici.

paretof = ParetoNBDFitter(penalizer_coef=PENALIZER_COEF)
paretof.fit(summary['frequency'], summary['recency'], summary['T'])
return paretof

Per generare risultati di CLV utilizzando il modello probabilistico nel tuo ambiente locale, puoi eseguire il seguente script mltrain.sh. Fornisci i parametri per le date di inizio e fine della suddivisione dell'addestramento e per la fine del periodo di previsione.

./mltrain.sh local data --model_type paretonbd_model --threshold_date [YOUR_THRESHOLD_DATE] --predict_end [YOUR_END_DATE]

Modelli DNN

Il codice campione include le implementazioni in TensorFlow di DNN utilizzando la classe dello strumento di stima predefinito DNNRegressor e un modello Estimator personalizzato. DNNRegressor e lo strumento di stima personalizzato utilizzano lo stesso numero di livelli e numero di neuroni in ogni livello. Questi valori sono iperparametri che devono essere regolati. Nel seguente file task.py puoi trovare un elenco di alcuni degli iperparametri impostati su valori che sono stati testati manualmente e che hanno dato buoni risultati.

TRAIN_SIZE = 100000
NUM_EPOCHS = 70
BATCH_SIZE = 5
NUM_EVAL = 20

LEARNING_DECAY_RATE = 0.7
HIDDEN_UNITS = '128 64 32 16'
LEARNING_RATE = 0.00135
L1_REGULARIZATION = 0.0216647
L2_REGULARIZATION = 0.0673949
DROPOUT = 0.899732
SHUFFLE_BUFFER_SIZE = 10000

Se utilizzi AI Platform, puoi utilizzare la funzionalità di ottimizzazione di iperparametri, che testerà una serie di parametri da te definiti in un file yaml. AI Platform utilizza l'ottimizzazione bayesiana per eseguire ricerche nello spazio degli iperparametri.

Risultati del confronto dei modelli

La tabella seguente mostra i valori RMSE per ogni modello, addestrati sul set di dati di esempio. Tutti i modelli sono addestrati sui dati RFM. I valori RMSE variano leggermente tra le esecuzioni, a causa dell'inizializzazione dei parametri casuali. Il modello DNN utilizza funzionalità aggiuntive come il valore medio del carrello e il numero di resi.

Modello RMSE
Non disturbare 947,9
BG/NBD 1557
Pareto 1558

I risultati mostrano che in questo set di dati il modello DNN ha un rendimento migliore rispetto ai modelli probabilistici quando prevede il valore monetario. Tuttavia, le dimensioni relativamente piccole del set di dati UCI limitano la validità statistica di questi risultati. Dovresti provare ciascuna delle tecniche sul tuo set di dati per vedere quale fornisce i risultati migliori. Tutti i modelli sono stati addestrati utilizzando gli stessi dati originali (inclusi ID cliente, data dell'ordine e valore dell'ordine) sui valori RFM estratti da questi dati. I dati di addestramento del DNN includevano alcune funzionalità aggiuntive, come la dimensione media del carrello e il numero di resi.

Il modello DNN genera solo il valore monetario complessivo del cliente. Se sei interessato a prevedere la frequenza o il tasso di abbandono, devi eseguire alcune attività aggiuntive:

  • Prepara i dati in modo diverso per modificare il target e, eventualmente, la data di soglia.
  • Reimposta un modello di regressione per prevedere il target che ti interessa.
  • Regola gli iperparametri.

Lo scopo era fare un confronto sulle stesse funzionalità di input tra i due tipi di modelli. Uno dei vantaggi di utilizzare i DNN è che potresti migliorare i risultati aggiungendo più funzionalità di quelle utilizzate in questo esempio. Con i DNN puoi utilizzare dati di origini come eventi di clickstream, profili utente o funzionalità del prodotto.

Ringraziamenti

Dua, D. e Karra Taniskidou, E. (2017). Repository di machine learning UCI http://archivio.ics.uci.edu/ml. Irvine, CA: University of California, School of Information and Computer Science.

Passaggi successivi