Test AB bayesiano con Pyro

Test AB bayesiano con Pyro Ottieni risultato

Una guida introduttiva al pensiero bayesiano e al test AB utilizzando Pyro

Credit: Free-Photos su Pixabay

Questo articolo è un’introduzione al test AB utilizzando il linguaggio di programmazione delle probabilità Python (PPL) Pyro, un’alternativa a PyMC. La motivazione dietro la scrittura di questo articolo è stata approfondire la mia comprensione del ragionamento statistico bayesiano utilizzando il framework Pyro e aiutare gli altri nel processo. Pertanto, il feedback è benvenuto ed è incoraggiato.

Introduzione

La mia precedente esperienza di modellazione bayesiana in Python era con PyMC. Tuttavia, ho trovato difficoltà a lavorare con alcune delle ultime versioni. La mia ricerca su altri linguaggi di programmazione probabilistica mi ha portato a scoprire Pyro, un PPL universale sviluppato da Uber e supportato da PyTorch sul backend. La documentazione di entrambi Pyro e PyTorch è collegata di seguito.

Pyro

Deep Universal Probabilistic Programming

pyro.ai

Documentazione PyTorch – Documentazione PyTorch 2.1

PyTorch è una libreri di tensori ottimizzata per l’apprendimento profondo utilizzando GPU e CPU. Le caratteristiche descritte in questa documentazione …

pytorch.org

Mentre esploravo Pyro, ho trovato difficile trovare tutorial completi per il test AB utilizzando il pacchetto. Questo articolo mira a colmare questa lacuna.

Questo articolo è diviso in cinque sezioni. Nella prima sezione, fornirò una guida introduttiva al pensiero bayesiano, un’analisi approfondita della filosofia che il metodo rappresenta. Fornirò una breve introduzione tecnica su Pyro e sui metodi bayesiani utilizzati per formulare le nostre inferenze statistiche. Successivamente, eseguirò un test AB utilizzando Pyro e ne discuterò i risultati. Spiegherò quindi il caso per il test AB bayesiano in un contesto aziendale. La sezione finale sarà un riassunto.

Una guida introduttiva al pensiero bayesiano

Il processo bayesiano è relativamente semplice a un alto livello. Innanzitutto, hai una variabile di tuo interesse. Esprimiamo la nostra comprensione attuale di tale variabile sotto forma di una distribuzione di probabilità (nel mondo di Bayes tutto è una distribuzione di probabilità). Questo è chiamato prior. La probabilità nell’inferenza bayesiana è epistemica, nel senso che deriva dal nostro grado di conoscenza. Pertanto, la distribuzione di probabilità che affermiamo come prior è sia una dichiarazione di incertezza che di comprensione. Successivamente, osserviamo eventi nel mondo reale. Queste osservazioni vengono quindi utilizzate per aggiornare la nostra comprensione della variabile di nostro interesse. Lo stato aggiornato della nostra comprensione viene chiamato posteriore. Caratterizziamo anche il posteriore con una distribuzione di probabilità, la probabilità della variabile di nostro interesse, dati i dati che abbiamo osservato. Questo processo è illustrato nel diagramma di flusso sottostante, in cui theta è la variabile di nostro interesse e i dati sono l’esito degli eventi che abbiamo osservato.

Processo bayesiano

Il processo bayesiano è in realtà ciclico, perché ripetiamo questo processo, ricominciando ma utilizzando la nostra nuova conoscenza appena acquisita dopo aver osservato il mondo. Il nostro vecchio posteriore diventa il nostro nuovo prior, osserviamo nuovi eventi e ancora una volta aggiorniamo la nostra comprensione, diventando “sempre meno sbagliati” come ha scritto Nate Silver nel suo libro “The Signal and the Noise”. Riduciamo continuamente l’incertezza riguardante la variabile, avvicinandoci a uno stato di certezza (ma non possiamo mai essere certi). Matematicamente, questo modo di pensare è racchiuso dal teorema di Bayes.

Teorema di Bayes

Praticamente, il teorema di Bayes diventa rapidamente computazionalmente intrattabile per modelli complessi in dimensioni superiori. Ci sono numerosi approcci per risolvere questo problema, ma il metodo che useremo oggi si chiama Markov Chain Monte Carlo, o MCMC. MCMC è una classe di algoritmi (useremo uno chiamato Hamiltonian Monte Carlo), che estrae campioni da una distribuzione di probabilità in modo intelligente. È al di fuori dello scopo di questo articolo approfondire questo argomento, ma fornirò alcuni riferimenti utili alla fine per ulteriori letture. Per ora, è sufficiente sapere che il teorema di Bayes è troppo complesso per poter essere calcolato, quindi sfruttiamo il potere di algoritmi avanzati, come MCMC, per aiutarci. Questo articolo si concentrerà su MCMC usando Pyro. Tuttavia, Pyro enfatizza l’uso di Inferenza Variazionale Stocastica (SVI), un approccio basato sull’approssimazione, che non verrà trattato qui.

AB Testing con Pyro

Pensiamo ad un’azienda che ha progettato una nuova pagina di atterraggio del sito web e vuole capire l’impatto che avrà sulla conversione, ovvero se i visitatori continuano la sessione web sul sito dopo essere atterrati sulla pagina? Nel gruppo di test A, ai visitatori del sito web verrà mostrata la pagina di atterraggio attuale. Nel gruppo di test B, ai visitatori del sito web verrà mostrata la nuova pagina di atterraggio. Nel resto dell’articolo, farò riferimento al gruppo di test A come gruppo di controllo e al gruppo B come gruppo di trattamento. L’azienda è scettica riguardo al cambiamento e ha optato per una divisione del traffico delle sessioni del 80/20. Il numero totale di visitatori e il numero totale di conversioni di pagina per ciascun gruppo di test vengono riassunti di seguito.

Osservazioni di test

L’ipotesi nulla del test AB è che non ci sarà alcun cambiamento nella conversione delle pagine per i due gruppi di test. Nel framework frequentista, questo sarebbe espresso come segue per un test a due code, dove r_c e r_t sono i tassi di conversione della pagina nei gruppi di controllo e trattamento, rispettivamente.

Ipotesi nulla e alternativa

Un test di significatività cercherebbe quindi di respingere o meno l’ipotesi nulla. Nel framework bayesiano, esprimiamo l’ipotesi nulla leggermente diversa, affermando lo stesso prior per ciascuno dei gruppi di test.

Facciamo una pausa e cerchiamo di definire esattamente cosa sta succedendo durante il nostro test. La variabile che ci interessa è il tasso di conversione delle pagine. Questo viene semplicemente calcolato prendendo il numero di visitatori convertiti distinti sul totale dei visitatori. L’evento che genera questo tasso è se il visitatore fa clic sulla pagina. Ci sono solo due possibili risultati qui per ogni visitatore, o il visitatore fa clic sulla pagin

Notazione della distribuzione Beta

Con accesso ai dati storici, possiamo affermare un prior informato. Non è necessario avere dati storici, potremmo utilizzare la nostra intuizione per informare la nostra comprensione, ma per ora assumiamo di non averne né (successivamente in questo tutorial utilizzeremo prior informati, ma per dimostrare l’impatto, inizierò con quelli non informati). Assumiamo di non avere comprensione del tasso di conversione sul sito dell’azienda e quindi definiamo il nostro prior come Beta(1,1). Questo è chiamato un prior piatto. La distribuzione di probabilità di questa funzione assomiglia al grafico sottostante, lo stesso di una distribuzione uniforme definita tra gli intervalli [0,1]. Affermando un prior Beta(1,1), diciamo che tutti i possibili valori del tasso di conversione della pagina sono altrettanto probabili.

Credit: Autore

Ora abbiamo tutte le informazioni necessarie, i prior e i dati. Passiamo al codice. Il codice fornito in questo documento fornisce un framework per iniziare con i test AB utilizzando Pyro; pertanto trascura alcune funzionalità del pacchetto. Per ottimizzare ulteriormente il codice e sfruttare al meglio le capacità di Pyro, consiglio di consultare la documentazione ufficiale.

Innanzitutto, dobbiamo importare i nostri pacchetti. L’ultima riga è una buona pratica, specialmente quando si lavora con notebook, per eliminare i parametri accumulati nella memoria.

import pyroimport pyro.distributions as distfrom pyro.infer import NUTS, MCMCimport torchfrom torch import tensorimport matplotlib.pyplot as pltimport seaborn as snsfrom functools import partialimport pandas as pdpyro.clear_param_store()

I modelli in Pyro sono definiti come funzioni Python normali. Questo è utile perché lo rende intuitivo da seguire.

def model(beta_alpha, beta_beta):    def _model_(traffic: tensor, number_of_conversions: tensor):        # Definisci primitive stocastiche        prior_c = pyro.sample('prior_c', dist.Beta(beta_alpha, beta_beta))        prior_t = pyro.sample('prior_t', dist.Beta(beta_alpha, beta_beta))        priors = torch.stack([prior_c, prior_t])        # Definisci primitive stocastiche osservate        with pyro.plate('data'):            observations = pyro.sample('obs', dist.Binomial(traffic, priors),\                             obs = number_of_conversions)    return partial(_model_)

Alcune cose da analizzare e spiegare qui. Prima di tutto, abbiamo una funzione avvolta all’interno di una funzione esterna, la funzione esterna restituisce la funzione parziale della funzione interna. Ciò ci consente di cambiare i nostri prior senza dover cambiare il codice. Ho fatto riferimento alle variabili definite nella funzione interna come primitive, pensa alle primitive come variabili nel modello. Abbiamo due tipi di primitive nel modello, primitive stocastiche e primitive stocastiche osservate. In Pyro non dobbiamo definire esplicitamente la differenza, semplicemente aggiungiamo l’argomento “obs” al metodo “sample” quando è una primitiva osservata e Pyro lo interpreta di conseguenza. Le primitive osservate sono contenute nel contesto di gestore pyro.plate(), che è una buona pratica e rende il nostro codice più pulito. Le nostre primitive stocastiche sono i nostri due prior, caratterizzati da distribuzioni Beta, governate dai parametri alpha e beta che passiamo dalla funzione esterna. Come già detto, affermiamo l’ipotesi nulla definendo queste come uguali. Dopo di ciò, sovrapponiamo queste due primitive utilizzando tensor.stack(), che esegue un’operazione simile alla concatenazione di un array Numpy. Questo restituirà un tensore, la struttura dati richiesta per l’inferenza in Pyro. Abbiamo definito il nostro modello, ora passiamo alla fase dell’inferenza.

Come già accennato, in questo tutorial useremo MCMC. La funzione di seguito prenderà il modello che abbiamo definito in precedenza e il numero di campioni che desideriamo utilizzare per generare la nostra distribuzione posteriore come parametro. Passiamo anche i nostri dati alla funzione, come abbiamo fatto per il modello.

def run_infernce(model, number_of_samples, traffic, number_of_conversions):    kernel = NUTS(model)    mcmc = MCMC(kernel, num_samples = number_of_samples, warmup_steps = 200)    mcmc.run(traffic, number_of_conversions)    return mcmc

La prima riga all’interno di questa funzione definisce il nostro kernel. Utilizziamo la classe NUTS per definire il nostro kernel, che sta per No-U-Turn Sampler, una versione di Hamiltonian Monte Carlo a tuning automatico. Questo dice a Pyro come campionare dallo spazio di probabilità posteriore. Ancora una volta, è al di là dello scopo di questo articolo approfondire questo argomento, ma per ora è sufficiente sapere che NUTS ci consente di campionare in modo intelligente dallo spazio di probabilità. Il kernel viene quindi utilizzato per inizializzare la classe MCMC nella seconda riga, specificando di utilizzare NUTS. Passiamo l’argomento number_of_samples nella classe MCMC, che è il numero di campioni utilizzati per generare la distribuzione posteriore. Assegniamo la classe MCMC inizializzata alla variabile mcmc e chiamiamo il metodo run(), passando i nostri dati come parametri. La funzione restituisce la variabile mcmc.

Questo è tutto ciò di cui abbiamo bisogno; il codice seguente definisce i nostri dati e chiama le funzioni che abbiamo appena creato utilizzando la distribuzione prior Beta(1,1).

traffic = torch.tensor([5523., 1379.])conversions =torch.tensor([2926., 759.])inference = run_infernce(model(1,1), number_of_samples = 1000, \               traffic = traffic, number_of_conversions = conversions)

Il primo elemento dei tensori traffic e conversions sono i conteggi per il gruppo di controllo, e il secondo elemento in ogni tensore sono i conteggi per il gruppo di trattamento. Passiamo la funzione model, con i parametri per governare la nostra distribuzione prior, insieme ai tensori che abbiamo definito. Eseguendo questo codice generiamo i nostri campioni posteriori. Eseguiamo il seguente codice per estrarre i campioni posteriori e passarli a un dataframe di Pandas.

posterior_samples = inference.get_samples()posterior_samples_df = pd.DataFrame(posterior_samples)

Osserva i nomi delle colonne di questo dataframe sono le stringhe che abbiamo passato quando abbiamo definito i nostri primi nella funzione model. Ogni riga nel nostro dataframe contiene campioni tratti dalla distribuzione posteriore, e ognuno di questi campioni rappresenta una stima del tasso di conversione della pagina, il valore di probabilità p che governa la nostra distribuzione binomiale. Ora che abbiamo ottenuto i campioni, possiamo plottare le nostre distribuzioni posteriori.

Risultati

Un modo illuminante per visualizzare i risultati del test AB con due gruppi di test è tramite un grafico di densità congiunta del kernel. Ci consente di visualizzare la densità di campioni nello spazio di probabilità in entrambe le distribuzioni. Il grafico sottostante può essere generato dal dataframe che abbiamo appena costruito.

Credit: Author

Lo spazio di probabilità contenuto nel grafico sopra può essere diviso diagonalmente, qualsiasi cosa sopra la linea indicherebbe regioni in cui la stima del tasso di conversione è maggiore nel gruppo di trattamento rispetto al gruppo di controllo e viceversa. Come illustrato nel grafico, i campioni tratti dal posteriore sono densamente popolati nella regione che indicherebbe che il tasso di conversione è maggiore nel gruppo di trattamento. È importante sottolineare che la distribuzione posteriore per il gruppo di trattamento è più ampia rispetto al gruppo di controllo, riflettendo un maggior grado di incertezza. Questo è il risultato di osservare meno dati nel gruppo di trattamento. Tuttavia, il grafico indica chiaramente che il gruppo di trattamento ha superato il gruppo di controllo. Raccogliendo un array di campioni dal posteriore e prendendo la differenza elemento per elemento, possiamo dire che la probabilità che il gruppo di trattamento superi il gruppo di controllo è del 90,4%. Questo numero suggerisce che il 90,4% dei campioni estratti dal posteriore sarà situato sopra la diagonale nel grafico di densità congiunta sopra.

Questi risultati sono stati ottenuti utilizzando una distribuzione prior piatta (non informativa). L’uso di una distribuzione prior informata potrebbe aiutare a migliorare il modello, specialmente quando la disponibilità di dati osservati è limitata. Una utile esercitazione consiste nel esplorare gli effetti dell’uso di diverse priors. Il grafico sottostante mostra la funzione di densità di probabilità Beta(2,2) e il grafico congiunto che produce quando ri-eseguiamo il modello. Possiamo vedere che l’uso della distribuzione prior Beta(2,2) produce una distribuzione posteriore molto simile per entrambi i gruppi di test.

Credit: Author

I campioni tratti dal posteriore suggeriscono che c’è una probabilità del 91,5% che il gruppo di trattamento si comporti meglio del controllo. Pertanto, crediamo con un grado di certezza maggiore che il gruppo di trattamento sia migliore del controllo rispetto all’uso di una prior piatta. Tuttavia, in questo esempio la differenza è trascurabile.

C’è un’altra cosa che vorrei evidenziare su questi risultati. Quando abbiamo eseguito l’analisi, abbiamo detto a Pyro di generare 1000 campioni dal postumo. Questo è un numero arbitrario, selezionare un numero diverso di campioni può cambiare i risultati. Per evidenziare l’effetto dell’aumento del numero di campioni, ho eseguito un test AB in cui le osservazioni dei gruppi di controllo e di trattamento erano le stesse, ciascuna con un tasso di conversione totale del 50%. Utilizzando un prior Beta(2,2) genera le seguenti distribuzioni posteriori incrementando progressivamente il numero di campioni.

Credit: Autore

Quando eseguiamo la nostra inferenza con solo 10 campioni, la distribuzione posteriore per i gruppi di controllo e di trattamento è relativamente ampia e assume forme diverse. Man mano che il numero di campioni che estraiamo aumenta, le distribuzioni convergono, generando infine distribuzioni praticamente identiche. Inoltre, osserviamo due proprietà delle distribuzioni statistiche, il teorema del limite centrale e il teorema dei grandi numeri. Il teorema del limite centrale afferma che la distribuzione delle medie campionarie converge verso una distribuzione normale con l’aumentare del numero di campioni, e possiamo vederlo nel grafico sopra. Inoltre, il teorema dei grandi numeri afferma che, all’aumentare della dimensione del campione, la media campionaria converge verso la media della popolazione. Possiamo vedere che la media delle distribuzioni nel riquadro in basso a destra è approssimativamente dello 0,5, il tasso di conversione osservato in ciascuno dei campioni di test.

Il caso aziendale per il test AB bayesiano

Il test AB bayesiano può contribuire a elevare la cultura del test e dell’apprendimento di un’azienda. L’inferenza statistica bayesiana consente di rilevare rapidamente piccoli aumenti nel test, poiché non si basa su probabilità a lungo termine per trarre conclusioni. Le conclusioni del test possono essere raggiunte più velocemente e quindi il ritmo di apprendimento aumenta. Il test AB bayesiano consente anche di interrompere anticipatamente un test, se i risultati ottenuti attraverso l ‘ “occhiolino” indicano che i gruppi di test stanno svolgendo un ruolo significativamente peggiore rispetto al controllo, il test può essere interrotto. Pertanto, il costo opportunità del test può essere significativamente ridotto. Questo è un vantaggio importante del test AB bayesiano; i risultati possono essere costantemente monitorati e i nostri posteriori costantemente aggiornati. Inoltre, la rilevazione precoce di un aumento del soggetto di test può aiutare le aziende a implementare più rapidamente i cambiamenti, riducendo la latenza nell’implementazione di cambiamenti che migliorano il fatturato. Le aziende che si rivolgono ai clienti devono essere in grado di implementare e analizzare rapidamente i risultati dei test, ciò che viene facilitato dal framework del test AB bayesiano.

Riassunto

Questo articolo ha fornito una breve introduzione al pensiero bayesiano ed esplorato i risultati del test AB bayesiano usando Pyro. Spero che tu abbia trovato questo articolo interessante. Come menzionato nell’introduzione, il feedback è benvenuto e incoraggiato. Come promesso, ho collegato di seguito alcuni materiali di approfondimento.

Materiale consigliato

I seguenti libri forniscono una buona comprensione dell’inferenza bayesiana:

  • The Signal and the Noise: The Art and Science of Prediction — Nate Silver
  • The Book of Why: The New Science of Cause and Effect — Judea Pearl e Dana Mackenzie. Anche se questo libro si focalizza principalmente sulla causalità, il capitolo 3 è una lettura interessante su Bayes’.
  • Bayesian Methods for Hackers: Probabilistic Programming and Bayesian Inference — Cameron Davidson-Pilon. Questo libro è disponibile anche su Git, ho messo il link qui sotto.

GitHub — CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers: aka “Bayesian…

aka “Bayesian Methods for Hackers”: Un’introduzione ai metodi bayesiani + programmazione probabilistica con a…

github.com

Questi articoli VoAGI forniscono spiegazioni dettagliate dell’MCMC.

Monte Carlo Markov Chain (MCMC) spiegato

I metodi MCMC sono una famiglia di algoritmi che utilizzano le catene di Markov per eseguire una stima di Monte Carlo.

towardsdatascience.com

Problema dell’inferenza Bayesiana, MCMC e inferenza variazionale

Panoramica del problema dell’inferenza Bayesiana nella statistica.

towardsdatascience.com