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

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

Gli articoli di questa serie sono i seguenti:

Il codice per implementare questo sistema è in una Repository GitHub. Questa serie illustra lo scopo del codice e come viene utilizzato.

Introduzione

Questo articolo segue Parte 1, in cui hai appreso due diversi modelli di previsione del lifetime dell'utente (CLV):

  • Modelli probabilistici
  • Modelli di reti neurali profonde (DNN), un tipo di modello 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 e creare e addestrare entrambi i tipi di modello per prevedere il CLV e fornire informazioni sul confronto.

Installazione del codice

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

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

    VAI A Cloud Shell

  2. Clona il repository di codice campione:

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

Preparazione dei dati

Questa sezione descrive come ottenere i dati e pulirli.

Ottenere e pulire il set di dati di origine

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

  • Un ID cliente utilizzato per distinguere i singoli clienti.
  • Un importo di acquisto per cliente che mostra quanto un cliente ha speso in un determinato momento.
  • Una data per ogni acquisto.

In questo articolo viene illustrato come addestrare i modelli utilizzando i dati storici sulle vendite dal bucket Cloud Storage Set di dati sulla vendita al dettaglio online provenienti dall'UCI Machine Learning Repository.[1]

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

  1. Sul computer o in Cloud Shell, esegui i comandi descritti nella sezione di 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 in cui la colonna Used è impostata su Yes. Alcuni campi non sono vengono utilizzati direttamente, ma consentono di creare nuovi campi, ad esempio UnitPrice e Quantity creano order_value.

Usato Campo Tipo Descrizione
No InvoiceNo STRING Nominale. Un numero intero di 6 cifre assegnato in modo univoco a ogni transazione. Se questo codice inizia con la lettera c, indica una cancellazione.
No StockCode STRING Codice prodotto (articolo). Nominale, un numero intero di 5 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. Valore numerico. Il prezzo del prodotto per unità in sterline.
CustomerID STRING Numero cliente. Nominale. Un numero intero di 5 cifre assegnato in modo univoco a ogni cliente.
No Country STRING Nome del paese. Nominale. Il nome del paese in cui risiede ciascun cliente.

pulisci i dati

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

  1. Raggruppa gli ordini per giorno invece di utilizzare 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. Mantieni solo i record con quantità di ordine e valori monetari positivi, come gli acquisti.
  4. Mantieni solo i record con quantità dell'ordine negative, ad esempio i resi.
  5. Conserva solo dati con un ID cliente.
  6. Mantieni solo i clienti che hanno acquistato qualcosa negli ultimi 90 giorni.
  7. Conserva solo i clienti che hanno effettuato almeno due acquisti nel periodo di tempo seguente per creare caratteristiche.

Puoi eseguire tutte queste operazioni utilizzando la seguente query BigQuery. Come per i comandi precedenti, esegui questo codice ovunque tu abbia clonato il repository GitHub. Poiché i dati sono vecchi, 12 dicembre 2011, è considerata la data odierna ai fini del presente 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à. In primo luogo, se il set di dati di lavoro è grande, query la riduce. Il set di dati di lavoro 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, simile al 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 ripulito 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 per la soglia. Questa data separa gli ordini in due partizioni:

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

Cronologia delle vendite per 4 clienti che mostra una data di soglia

La libreria Lifetime include metodi per la pre-elaborazione dei dati. Tuttavia, i set di dati che utilizzi per il CLV possono essere piuttosto grandi, il che rende impraticabile eseguire la pre-elaborazione dei dati su una singola macchina. L'approccio descritto in utilizza query eseguite direttamente in BigQuery per suddividere gli ordini in due insiemi. I modelli ML e probabilistici utilizzano le stesse query, garantendo che entrambi i modelli operino sugli stessi dati.

La data di soglia ottimale potrebbe variare per i modelli ML e per di grandi dimensioni. Puoi aggiornare il valore della data direttamente all'interno dell'istruzione SQL. Considera la data di soglia ottimale come un iperparametro. Per trovare il valore più appropriato, esplora i dati ed esegui alcuni test corsi di formazione.

La data di soglia viene utilizzata nella clausola WHERE della query SQL che seleziona di addestramento dalla tabella dei dati puliti, 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 target, li aggreghi per creare funzionalità e target effettivi per ogni cliente. Per i modelli probabilistici, l'aggregazione è limitata ai campi di recency, frequenza e valore monetario (RFM). Per I modelli DNN utilizzano anche caratteristiche RFM ma possono utilizzare caratteristiche aggiuntive per per fare previsioni migliori.

La seguente query mostra come creare contemporaneamente funzionalità sia per i modelli DNN sia per quelli 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 gli elementi creati dalla query.

Nome della funzionalità Descrizione Probabilistico DNN
monetary_dnn La somma di tutti gli ordini valori monetari per cliente durante le funzionalità punto. x
monetary_btyd La media di tutti gli ordini i valori monetari per ciascun cliente durante caratteristiche. I modelli probabilistici presuppongono che il valore del primo ordine sia 0. Questa operazione viene applicata in modo forzato dalla query. x
recency Il tempo che intercorre tra il primo e l'ultimo ordine effettuati da un cliente durante il periodo delle funzionalità. x
frequency_dnn Il numero di ordini effettuati da un cliente durante il periodo delle funzionalità. x
frequency_btyd Il numero di ordini effettuati da un cliente durante il periodo delle funzionalità meno la prima. x
T Il tempo che intercorre tra il primo ordine effettuato da un cliente e la fine della caratteristiche. x x
time_between Il tempo medio tra un ordine e l'altro per un cliente durante il periodo di funzionalità. x
avg_basket_value Il valore monetario medio del carrello del cliente durante il periodo di 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 che il cliente ha restituito durante le funzionalità punto. x
has_returned Se il cliente ha restituito almeno un ordine durante le funzionalità punto. x
frequency_btyd_clipped Uguale a frequency_btyd, ma in corrispondenza dei valori anomali. x
monetary_btyd_clipped Uguale a monetary_btyd, ma con valori estremi tagliati dal limite. x
target_monetary_clipped Uguale a target_monetary, ma con valori estremi tagliati dal limite. 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 eseguita utilizzando 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 caratteristiche di TensorFlow sono definite context.py. Per questi modelli, le seguenti caratteristiche vengono ignorate come caratteristiche:

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

Creazione dei set di addestramento, valutazione e test per DNN

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

  • Il set di dati per l'addestramento (70-80%) viene utilizzato per apprendere i pesi al fine di ridurre funzione di perdita di dati. L'addestramento continua finché la funzione di perdita non diminuisce più.

  • Il set di dati di valutazione (10-15%) viene utilizzato durante la fase di addestramento per prevenire overfitting, ovvero quando un modello funziona bene sui dati di addestramento, generalizza bene.

  • Il set di dati di test (10-15%) deve essere utilizzato una sola volta, al termine dell'addestramento e della valutazione, per eseguire una misurazione finale del rendimento del modello. Questo set di dati non è mai stato visto dal modello durante il processo di addestramento, pertanto fornisce una misura statisticamente valida dell'accuratezza del modello.

La seguente query 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 genera un numero intero.
  • Un'operazione modulo viene utilizzata per selezionare i valori hash che sono al di sotto di un una certa 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 per i set di test, dove i dati al di sopra della soglia.

Formazione

Come hai visto nella sezione precedente, puoi usare modelli diversi per provare 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 passi al seguente script shell di addestramento. Il codice si occupa delle attività e riposare.

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 battere un benchmark ingenuo, che definiamo di seguito. Se entrambi i tipi di modelli possono battere questo problema (e dovrebbe), puoi confrontare il rendimento di ciascun tipo rispetto all'altro.

Benchmarking dei modelli

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

  • Valore medio del carrello. Questo valore viene calcolato su tutti gli ordini effettuati prima della data di soglia.
  • Conteggio degli ordini. Viene calcolato per l'intervallo di addestramento di tutti gli ordini posizionati prima della data di soglia.
  • Moltiplicatore del conteggio. Questo valore viene calcolato in base al rapporto tra il numero giorni prima della data della soglia e il numero di giorni tra la soglia data e ora.

Il benchmark presuppone ingenuamente che la percentuale di acquisti stabilita da un cliente durante l'intervallo di addestramento rimanga costante nell'intervallo di destinazione. Quindi, se un cliente ha effettuato 6 acquisti in 40 giorni, si presume che compreranno 9 volte in 60 giorni (60/40 * 6 = 9). Moltiplica il conteggio moltiplicatore, il numero degli ordini e il valore medio del carrello per ciascun cliente fornisce un valore target previsto ingenuo per quel cliente.

L'errore del benchmark è l'errore quadratico medio (RMSE): la media tra tutti gli utenti della differenza assoluta tra il valore target previsto e il valore target effettivo. L'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 pari a 3760, come mostrato nei seguenti risultati di eseguendo il benchmark. I modelli dovrebbero superare questo valore.

Risultati dei benchmark

Modelli probabilistici

Come accennato nella Parte 1 di questa serie, questa utilizza una libreria Python chiamata Lifetimes che supporta vari modelli, tra cui la distribuzione Pareto/binomiale negativa (NBD) e i modelli BG/NBD beta-geometrici. Il seguente codice di esempio mostra come utilizzare la libreria Lifetimes per eseguire previsioni sul 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 account puoi eseguire il seguente script mltrain.sh. Fornisci parametri per le date di inizio e di 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 di esempio include implementazioni in TensorFlow di reti neurali profonde che utilizzano la classe Estimator DNNRegressor predefinita, nonché un modello Estimator personalizzato. DNNRegressor e l'estimatore personalizzato utilizzano lo stesso numero di strati e neuroni in ogni livello. Questi valori sono iperparametri che devono essere ottimizzati. Nel seguente file task.py puoi trovare un elenco di alcuni degli iperparametri impostati su valori 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 ottimizzazione degli iperparametri che eseguirà il test su una serie di parametri da te definiti in un file YAML . AI Platform utilizza Ottimizzazione bayesiana per cercare nello spazio degli iperparametri.

Risultati del confronto tra i modelli

La tabella seguente mostra i valori RMSE per ciascun modello, come addestrati sulla base un set di dati di esempio. Tutti i modelli vengono 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
DNN 947,9
BG/NBD 1557
Pareto/NBD 1558

I risultati mostrano che su questo set di dati, il modello DNN supera i modelli probabilistici nella previsione del valore monetario. Tuttavia, relativamente le dimensioni ridotte del set di dati UCI limitano la validità statistica di questi risultati. Ti consigliamo di provare ciascuna delle tecniche sul tuo set di dati per scoprire quale offre i risultati migliori. Tutti i modelli sono stati addestrati utilizzando gli stessi dati originali (inclusi ID cliente, data ordine e valore ordine) sui valori RFM che sono stati estratto da questi dati. I dati di addestramento della rete neurale di tipo DNN includevano alcune funzionalità aggiuntive come la dimensione media del carrello e il numero di resi.

Il modello DNN restituisce solo il valore monetario complessivo del cliente. Se ti interessa predire la frequenza o il tasso di abbandono, devi eseguire alcune attività aggiuntive:

  • Prepara i dati in modo diverso per modificare il target e possibilmente la data di soglia.
  • Addestra nuovamente un modello di regressione per prevedere il target che ti interessa.
  • Ottimizza gli iperparametri.

Lo scopo in questo caso era eseguire un confronto sulle stesse caratteristiche di input tra i due tipi di modelli. Un vantaggio dell'utilizzo delle DNN è che puoi migliorare i risultati aggiungendo più caratteristiche rispetto a quelle utilizzate in questo esempio. Con per le reti DNN, puoi sfruttare i dati provenienti da origini come eventi di flusso di clic, profili utente o funzionalità del prodotto.

Ringraziamenti

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

Passaggi successivi