Credito: NewsWire, The TakeOut.

Come costruire un sistema di consigli per i dati di acquisto (passo-passo)

Un'applicazione di filtro collaborativo basato su elementi con Turicreate e Python

Sia che tu sia responsabile dell'esperienza utente e della strategia di prodotto in un'azienda incentrata sul cliente, o seduto sul divano a guardare film con i propri cari, è probabile che tu sia già a conoscenza di alcuni modi in cui la tecnologia di raccomandazione viene utilizzata per personalizzare i tuoi contenuti e le tue offerte.

I sistemi di raccomandazione sono una delle applicazioni più comuni e facilmente comprensibili dei big data e dell'apprendimento automatico. Tra le applicazioni più conosciute ci sono il motore di consigli di Amazon che ci fornisce una pagina web personalizzata quando visitiamo il sito e l'elenco di consigli di Spotify di canzoni quando ascoltiamo usando la loro app.

L'ultima volta, abbiamo realizzato un Discover Weekly di Spotify con una grande quantità di dati audio utilizzando Spark. Questa volta, creeremo un motore di raccomandazione per articoli più tangibili.

La sfida

Se cerchi online, ci sono molti modi per creare sistemi di raccomandazione per dati basati su rating, come film e canzoni. Il problema con i modelli basati su rating è che non potevano essere standardizzati facilmente per i dati con valori target non ridimensionati, come i dati di acquisto o di frequenza. Ad esempio, le classificazioni sono generalmente comprese tra 0 e 5 o tra 0 e 10 tra brani e film. Tuttavia, i dati di acquisto sono continui e senza limite superiore.

Molte risorse online purtroppo forniscono risultati senza valutare i loro modelli. Per la maggior parte dei data scientist e ingegneri, questa è un'area pericolosa quando coinvolgi milioni di dati! Per i settori, i risultati da soli non portano i tuoi strumenti ovunque senza alcuna valutazione.

L'obiettivo. il gol

Nel risolvere questi problemi, costruiremo modelli di filtro collaborativo per consigliare i prodotti ai clienti utilizzando i dati di acquisto. In particolare, tratteremo in dettaglio il processo passo-passo nella costruzione di un sistema di raccomandazioni con Python e il modulo di apprendimento automatico Turicreate. Questi passaggi includono:

  • Trasformazione e normalizzazione dei dati
  • Modelli di allenamento
  • Valutazione delle prestazioni del modello
  • Selezione del modello ottimale

Panoramica del Prodotto

Immagina che una catena di generi alimentari rilasci una nuova app mobile che consenta ai suoi clienti di effettuare ordini prima ancora di dover entrare nel negozio.

Vi è un'opportunità per l'app di mostrare consigli: quando un cliente tocca per la prima volta la pagina "ordina", possiamo raccomandare di aggiungere al suo carrello i 10 articoli principali, ad es. utensili usa e getta, carne fresca, patatine e così via.

Lo strumento sarà anche in grado di cercare un elenco di raccomandazioni basato su un utente specificato, in modo che:

  • Input: ID cliente
  • Resi: elenco classificato di articoli (ID prodotto), che è più probabile che l'utente desideri inserire nel suo "carrello" (vuoto)

Implementazione

1. Importare moduli

  • panda e numpy per la manipolazione dei dati
  • turicreate per eseguire la selezione e la valutazione del modello
  • sklearn per la suddivisione dei dati in treno e set di test
% load_ext Ricarica automatica
% caricamento automatico 2

importare i panda come pd
importa numpy come np
tempo di importazione
import turicreate come tc
da sklearn.cross_validation import train_test_split

import sys
sys.path.append ( "..")

2. Carica dati

Di seguito vengono utilizzati due set di dati in formato .csv, che è possibile trovare nella cartella dei dati qui:

  • recommend_1.csv costituito da un elenco di 1000 ID cliente da consigliare come output
  • trx_data.csv costituito da transazioni utente
clienti = pd.read_csv ('../ data / recommend_1.csv')
transazioni = pd.read_csv ('../ data / trx_data.csv')

3. Preparazione dei dati

Il nostro obiettivo qui è quello di scomporre ogni elenco di articoli nella colonna prodotti in righe e contare il numero di prodotti acquistati da un utente

3.1. Crea dati con campo utente, oggetto e destinazione

  • Questa tabella sarà un input per la nostra modellazione in seguito
  • In questo caso, il nostro utente è ID cliente, ID prodotto e conta_acquisto
data = pd.melt (transazioni.set_index ('customerId') ['products']. apply (pd.Series) .reset_index (),
             id_vars = [ 'customerId'],
             value_name = 'products') \
    .dropna (). drop (['variabile'], asse = 1) \
    .groupby (['customerId', 'products']) \
    .agg ({'products': 'count'}) \
    .rename (colonne = {'prodotti': 'acquisto_conto'}) \
    .reset_index () \
    .rename (colonne = {'products': 'productId'})
data ['productId'] = data ['productId']. astype (np.int64)

3.2. Crea un manichino

  • Manichino per indicare se un cliente ha acquistato quell'oggetto o meno.
  • Se si acquista un articolo, quindi acquisto_dummy sono contrassegnati come 1
  • Perché creare un manichino invece di normalizzarlo, chiedi? La normalizzazione del conteggio degli acquisti, ad esempio per ogni utente, non funzionerebbe perché i clienti potrebbero avere una frequenza di acquisto diversa e non avere lo stesso gusto. Tuttavia, possiamo normalizzare gli articoli in base alla frequenza di acquisto tra tutti gli utenti, come indicato nella sezione 3.3. sotto.
def create_data_dummy (dati):
    data_dummy = data.copy ()
    data_dummy ['purchase_dummy'] = 1
    return data_dummy
data_dummy = create_data_dummy (dati)

3.3. Normalizza i valori degli articoli tra gli utenti

  • Per fare ciò, normalizziamo la frequenza di acquisto di ciascun articolo tra gli utenti creando prima una matrice di articoli come segue
df_matrix = pd.pivot_table (data, valori = 'acquisto_conto', indice = 'customerId', colonne = 'productId')
df_matrix_norm = (df_matrix-df_matrix.min ()) / (df_matrix.max () - df_matrix.min ())
# crea una tabella per l'input alla modellazione
d = df_matrix_norm.reset_index ()
d.index.names = ['scaled_purchase_freq']
data_norm = pd.melt (d, id_vars = ['customerId'], value_name = 'scaled_purchase_freq'). dropna ()
stampa (data_norm.shape)
data_norm.head ()

I passaggi precedenti possono essere combinati con una funzione definita di seguito:

def normalize_data (dati):
    df_matrix = pd.pivot_table (data, valori = 'acquisto_conto', indice = 'customerId', colonne = 'productId')
    df_matrix_norm = (df_matrix-df_matrix.min ()) / (df_matrix.max () - df_matrix.min ())
    d = df_matrix_norm.reset_index ()
    d.index.names = ['scaled_purchase_freq']
    return pd.melt (d, id_vars = ['customerId'], value_name = 'scaled_purchase_freq'). dropna ()

In questo passaggio, abbiamo normalizzato la cronologia degli acquisti, da 0 a 1 (con 1 che rappresenta il maggior numero di acquisti per un articolo e 0 che sono 0 conteggi acquisti per quell'articolo).

4. Treno diviso e set di prova

  • La suddivisione dei dati in set di formazione e test è una parte importante della valutazione della modellazione predittiva, in questo caso un modello di filtro collaborativo. In genere, utilizziamo una parte maggiore dei dati per la formazione e una porzione più piccola per i test.
  • Usiamo il rapporto 80:20 per le dimensioni del nostro set treno-prova.
  • La nostra parte di formazione verrà utilizzata per sviluppare un modello predittivo, mentre l'altra per valutare le prestazioni del modello.

Definiamo una funzione di suddivisione di seguito.

def split_data (dati):
    '''
    Divide il set di dati in training e set di test.
    
    args:
        dati (panda.DataFrame)
        
    ritorna
        train_data (tc.SFrame)
        test_data (tc.SFrame)
    '''
    train, test = train_test_split (dati, test_size = .2)
    train_data = tc.SFrame (treno)
    test_data = tc.SFrame (test)
    return train_data, test_data

Ora che abbiamo tre set di dati con conteggi degli acquisti, acquisti fittizi e conteggi degli acquisti in scala, vorremmo dividerli ciascuno per la modellazione.

train_data, test_data = split_data (dati)
train_data_dummy, test_data_dummy = split_data (data_dummy)
train_data_norm, test_data_norm = split_data (data_norm)

5. Definire i modelli utilizzando la libreria Turicreate

Prima di eseguire un approccio più complicato come il filtro collaborativo, dovremmo eseguire un modello di base per confrontare e valutare i modelli. Poiché la linea di base utilizza in genere un approccio molto semplice, le tecniche utilizzate oltre questo approccio dovrebbero essere scelte se mostrano una precisione e una complessità relativamente migliori. In questo caso, useremo il modello di popolarità.

Un approccio più complicato ma comune per prevedere gli articoli acquistati è il filtro collaborativo. Discuterò di più sul modello di popolarità e sul filtro collaborativo nella sezione successiva. Per ora, per prima cosa definiamo le nostre variabili da utilizzare nei modelli:

# variabili costanti per definire i nomi dei campi includono:
user_id = 'customerId'
item_id = 'productId'
users_to_recommend = list (customers [user_id])
n_rec = 10 # numero di articoli da raccomandare
n_display = 30 # per visualizzare le prime poche righe in un set di dati di output

Turicreate ci ha reso estremamente facile chiamare una tecnica di modellazione, quindi definiamo la nostra funzione per tutti i modelli come segue:

modello def (train_data, name, user_id, item_id, target, users_to_recommend, n_rec, n_display):
    se name == 'popolarità':
        modello = tc.popularity_recommender.create (train_data,
                                                    user_id = user_id,
                                                    item_id = item_id,
                                                    target = target)
    nome elif == 'coseno':
        modello = tc.item_similarity_recommender.create (train_data,
                                                    user_id = user_id,
                                                    item_id = item_id,
                                                    target = bersaglio,
                                                    similarity_type = 'coseno')
nome elif == 'pearson':
        modello = tc.item_similarity_recommender.create (train_data,
                                                    user_id = id_utente,
                                                    item_id = item_id,
                                                    target = bersaglio,
                                                    similarity_type = 'Pearson')
        
    recom = model.recommend (utenti = users_to_recommend, k = n_rec)
    recom.print_rows (n_display)
    modello di ritorno

Mentre ho scritto script Python per tutto il processo di cui sopra, inclusa la ricerca di somiglianza utilizzando gli script Python (che possono essere trovati qui, per il momento utilizziamo la libreria turicreate per acquisire più rapidamente misure diverse e valutare modelli.

6. Modello di popolarità come base

  • Il modello di popolarità prende in considerazione gli articoli più popolari. Questi articoli sono prodotti con il maggior numero di vendite tra i clienti.
  • I dati di allenamento vengono utilizzati per la selezione del modello

io. Utilizzo del conteggio acquisti

name = 'popolarità'
target = 'purchase_count'
popolarità = modello (train_data, nome, user_id, item_id, target, users_to_recommend, n_rec, n_display)

ii. Utilizzo del manichino di acquisto

name = 'popolarità'
target = 'purchase_dummy'
pop_dummy = modello (train_data_dummy, nome, user_id, item_id, target, users_to_recommend, n_rec, n_display)

iii. Utilizzo del conteggio acquisti scalato

name = 'popolarità'
target = 'scaled_purchase_freq'
pop_norm = modello (train_data_norm, name, user_id, item_id, target, users_to_recommend, n_rec, n_display)

6.1. Riepilogo di base

  • Una volta creato il modello, abbiamo previsto gli articoli delle raccomandazioni utilizzando i punteggi in base alla popolarità. Come puoi vedere per i risultati di ciascun modello sopra, le righe mostrano i primi 30 record di 1000 utenti con 10 consigli. Questi 30 record includono 3 utenti e i loro articoli consigliati, insieme a punteggio e gradi decrescenti.
  • Nel risultato, sebbene modelli diversi abbiano un elenco di raccomandazioni diverso, a ogni utente viene consigliato lo stesso elenco di 10 elementi. Questo perché la popolarità viene calcolata prendendo gli articoli più popolari tra tutti gli utenti.
  • Se di seguito un esempio di raggruppamento, i prodotti 132, 248, 37 e 34 sono i più popolari (i più venduti) tra i clienti. Usando i conteggi degli acquisti divisi per il numero di clienti, vediamo che questi prodotti vengono almeno acquistati 3 volte in media nel set di transazioni di training (lo stesso della prima misura di popolarità sulla variabile acquisti_count)

7. Modello di filtro collaborativo

Nel filtro collaborativo, consigliamo gli articoli in base al modo in cui gli utenti simili acquistano gli articoli. Ad esempio, se il cliente 1 e il cliente 2 hanno acquistato articoli simili, ad es. 1 comprato X, Y, Z e 2 comprato X, Y, raccomandiamo un articolo Z al cliente 2.

7.1. Metodologia

Per definire la somiglianza tra gli utenti, utilizziamo i seguenti passaggi:

1. Creare una matrice articolo utente, in cui i valori dell'indice rappresentano ID cliente univoci e i valori colonna rappresentano ID prodotto univoci

2. Creare una matrice di somiglianza da articolo a articolo. L'idea è di calcolare quanto è simile un prodotto a un altro prodotto. Esistono diversi modi per calcolare questo. Nei passaggi 7.2 e 7.3, utilizziamo la misura della somiglianza del coseno o del pearson, rispettivamente.

  • Per calcolare la somiglianza tra i prodotti X e Y, guarda tutti i clienti che hanno valutato entrambi questi articoli. Ad esempio, sia X che Y sono stati valutati dai clienti 1 e 2.
  • Creiamo quindi due vettori oggetto, v1 per l'articolo X e v2 per l'articolo Y, nello spazio utente di (1, 2) e quindi troviamo l'angolo / distanza del coseno o di Pearson tra questi vettori. Un angolo zero o vettori sovrapposti con valore del coseno pari a 1 indicano una somiglianza totale (o per utente, su tutti gli articoli, hanno la stessa classificazione) e un angolo di 90 gradi significherebbe un coseno pari a 0 o nessuna somiglianza.

3. Per ciascun cliente, prevediamo quindi la sua probabilità di acquistare un prodotto (o i suoi conteggi di acquisto) per i prodotti che non aveva acquistato.

  • Nel nostro esempio, calcoleremo la valutazione per l'utente 2 nel caso dell'articolo Z (oggetto target). Per calcolare questo, pesiamo la misura di somiglianza appena calcolata tra l'oggetto target e altri articoli che il cliente ha già acquistato. Il fattore di ponderazione sono i conteggi degli acquisti forniti dall'utente agli articoli già acquistati da lui.
  • Quindi ridimensioniamo questa somma ponderata con la somma delle misure di somiglianza in modo che il rating calcolato rimanga entro limiti predefiniti. Pertanto, la valutazione prevista per l'articolo Z per l'utente 2 verrebbe calcolata utilizzando misure di somiglianza.

7.2. Somiglianza del coseno

  • La somiglianza è il coseno dell'angolo tra i 2 vettori degli oggetti vettori di A e B.
  • È definito dalla seguente formula
  • Più vicini sono i vettori, più piccolo sarà l'angolo e maggiore sarà il coseno

io. Utilizzo del conteggio acquisti

nome = 'coseno'
target = 'purchase_count'
cos = modello (train_data, name, user_id, item_id, target, users_to_recommend, n_rec, n_display)

ii. Utilizzo del manichino di acquisto

nome = 'coseno'
target = 'purchase_dummy'
cos_dummy = modello (train_data_dummy, nome, user_id, item_id, target, users_to_recommend, n_rec, n_display)

iii. Utilizzo del conteggio acquisti scalato

nome = 'coseno'
target = 'scaled_purchase_freq'
cos_norm = modello (train_data_norm, name, user_id, item_id, target, users_to_recommend, n_rec, n_display)

7.3. Somiglianza di Pearson

  • La somiglianza è il coefficiente pearson tra i due vettori.
  • È definito dalla seguente formula

io. Utilizzo del conteggio acquisti

name = 'pearson'
target = 'purchase_count'
pear = modello (train_data, name, user_id, item_id, target, users_to_recommend, n_rec, n_display)

ii. Utilizzo del manichino di acquisto

name = 'pearson'
target = 'purchase_dummy'
pear_dummy = modello (train_data_dummy, nome, user_id, item_id, target, users_to_recommend, n_rec, n_display)

iii. Utilizzo del conteggio acquisti scalato

name = 'pearson'
target = 'scaled_purchase_freq'
pear_norm = modello (train_data_norm, name, user_id, item_id, target, users_to_recommend, n_rec, n_display)

8. Valutazione del modello

Per valutare i motori di raccomandazione, possiamo usare il concetto di RMSE e richiamo di precisione.

io. RMSE (errori quadrati medi radice)

  • Misura l'errore dei valori previsti
  • Minore il valore RMSE, migliori i consigli

ii. Richiamare

  • Quale percentuale di prodotti acquistati da un utente è effettivamente consigliata?
  • Se un cliente acquista 5 prodotti e la raccomandazione ha deciso di mostrarne 3, il richiamo è 0,6

iii. Precisione

  • Di tutti gli articoli consigliati, quanti sono effettivamente piaciuti all'utente?
  • Se al cliente sono stati raccomandati 5 prodotti dai quali ne acquista 4, la precisione è 0,8

Perché sia ​​il richiamo che la precisione sono importanti?

  • Prendi in considerazione un caso in cui consigliamo tutti i prodotti, quindi i nostri clienti copriranno sicuramente gli articoli che hanno gradito e acquistato. In questo caso, abbiamo il 100% di richiamo! Questo significa che il nostro modello è buono?
  • Dobbiamo considerare la precisione. Se raccomandiamo 300 articoli ma all'utente piace e ne acquista solo 3, la precisione è dello 0,1%! Questa precisione molto bassa indica che il modello non è eccezionale, nonostante il loro eccellente richiamo.
  • Quindi il nostro obiettivo deve essere l'ottimizzazione del richiamo e della precisione (essere il più vicino possibile a 1).

Innanzitutto creiamo variabili richiamabili iniziali per la valutazione del modello:

models_w_counts = [popolarità_model, cos, pera]
models_w_dummy = [pop_dummy, cos_dummy, pear_dummy]
models_w_norm = [pop_norm, cos_norm, pear_norm]
names_w_counts = ["Modello di popolarità sui conteggi degli acquisti", "Somiglianza dei coseni sui conteggi degli acquisti", "Somiglianza di Pearson sui conteggi degli acquisti"]
names_w_dummy = ['Modello di popolarità sul manichino d'acquisto', 'Somiglianza del coseno sul manichino d'acquisto', 'Somiglianza Pearson sul manichino d'acquisto']
names_w_norm = ['Modello di popolarità sui conteggi degli acquisti in scala', 'Somiglianza del coseno sui conteggi degli acquisti in scala', 'Somiglianza Pearson sui conteggi degli acquisti in scala']

Consente di confrontare tutti i modelli che abbiamo costruito sulla base di RMSE e caratteristiche di richiamo di precisione:

eval_counts = tc.recommender.util.compare_models (test_data, models_w_counts, model_names = names_w_counts)
eval_dummy = tc.recommender.util.compare_models (test_data_dummy, models_w_dummy, model_names = names_w_dummy)
eval_norm = tc.recommender.util.compare_models (test_data_norm, models_w_norm, model_names = names_w_norm)

8.1. Uscita di valutazione

  • Basato su RMSE
  • Basato su precisione e richiamo

8.2. Riepilogo valutazione

  • Popolarità v. Filtro collaborativo: possiamo vedere che gli algoritmi di filtro collaborativo funzionano meglio del modello di popolarità per i conteggi degli acquisti. In effetti, il modello di popolarità non offre alcuna personalizzazione in quanto fornisce solo lo stesso elenco di articoli consigliati a tutti gli utenti.
  • Precisione e richiamo: osservando il riepilogo sopra, vediamo che la precisione e il richiamo per Conti acquisti> Manichino acquisti> Conti acquisti normalizzati. Tuttavia, poiché i punteggi delle raccomandazioni per i dati di acquisto normalizzati sono zero e costanti, scegliamo il manichino. In effetti, RMSE non è molto diverso tra i modelli sul manichino e quelli sui dati normalizzati.
  • RMSE: poiché RMSE è più elevato utilizzando la distanza di Pearson rispetto alla cosina, sceglieremmo il modello degli errori quadrati medi più piccoli, che in questo caso sarebbero coseno.
Pertanto, selezioniamo la somiglianza del coseno nell'approccio Dummy acquisto come modello finale.

9. Uscita finale

Infine, vorremmo manipolare il formato per l'output dei consigli su uno che possiamo esportare in CSV, e anche una funzione che restituirà l'elenco dei consigli dato un ID cliente.

Dobbiamo prima rieseguire il modello utilizzando l'intero set di dati, poiché siamo arrivati ​​a un modello finale utilizzando i dati del treno e valutato con il set di test.

final_model = tc.item_similarity_recommender.create (tc.SFrame (data_norm),
                                            user_id = user_id,
                                            item_id = item_id,
                                            target = 'purchase_dummy', similarity_type = 'cosine')
recom = final_model.recommend (utenti = users_to_recommend, k = n_rec)
recom.print_rows (n_display)

9.1. File di output CSV

Qui vogliamo manipolare il nostro risultato in un output CSV. Vediamo cosa abbiamo:

df_rec = recom.to_dataframe ()
stampa (df_rec.shape)
df_rec.head ()

Definiamo una funzione per creare l'output desiderato:

def create_output (modello, users_to_recommend, n_rec, print_csv = True):
    recomendation = model.recommend (users = users_to_recommend, k = n_rec)
    df_rec = recomendation.to_dataframe ()
    df_rec ['recommendedProducts'] = df_rec.groupby ([user_id]) [item_id] \
        .transform (lambda x: '|' .join (x.astype (str)))
    df_output = df_rec [['customerId', 'recommendedProducts']]. drop_duplicates () \
        .sort_values ​​( 'customerId'). set_index ( 'customerId')
    se print_csv:
        df_output.to_csv ( '../ uscita / option1_recommendation.csv')
        print ("È possibile trovare un file di output nella cartella 'output' con nome 'option1_recommendation.csv'")
    return df_output

Consente di stampare l'output di seguito e setprint_csv su true, in questo modo potremmo letteralmente stampare il nostro file di output in csv, che puoi trovare anche qui.

df_output = create_output (pear_norm, users_to_recommend, n_rec, print_csv = True)
stampa (df_output.shape)
df_output.head ()

9.2. Funzione di raccomandazione del cliente

Definiamo una funzione che restituirà l'elenco dei consigli dato un ID cliente:

def customer_recomendation (customer_id):
    se customer_id non è in df_output.index:
        print ('Cliente non trovato.')
        return customer_id
    return df_output.loc [customer_id]

Bingo!

Sommario

In questo articolo, siamo stati in grado di attraversare un processo passo-passo per formulare raccomandazioni ai clienti. Abbiamo utilizzato approcci di filtro collaborativo con misura Cosine e Pearson e confrontato i modelli con il nostro modello di popolarità di base.

Abbiamo anche preparato tre serie di dati che includono il conteggio degli acquisti regolari, l'acquisto di manichini e la frequenza di acquisto normalizzata come nostra variabile target. Usando RMSE, precisione e richiamo, abbiamo valutato i nostri modelli e osservato l'impatto della personalizzazione. Infine, abbiamo selezionato l'approccio Cosine utilizzando i dati fittizi come modello del nostro miglior sistema di raccomandazioni.

Spero ti piaccia leggere questo articolo e ora sei pronto per creare il tuo pulsante "aggiungi al carrello". Per favore dai 50 battiti e commenta qui sotto se vuoi più letture come questa :) Divertiti a fare hacking!

Moorissa è una scienziata di dati orientata alla missione e appassionata di impresa sociale. Nel dicembre 2017, si è laureata presso la Columbia University con uno studio di data science e machine learning. Spera di sfruttare sempre le sue abilità per rendere il mondo un posto migliore, un giorno alla volta.