2009-06-09 4 views
5

Ho un gruppo di dati in arrivo (chiamate a un call center automatico) sull'opportunità o meno di acquistare un particolare prodotto, 1 per l'acquisto, 0 per non acquistare.Stima di una probabilità data altre probabilità da un precedente

Desidero utilizzare questi dati per creare una probabilità stimata che una persona acquisterà un particolare prodotto, ma il problema è che potrebbe essere necessario farlo con dati storici relativamente bassi sul numero di persone che hanno acquistato/non acquistato quel prodotto.

Un amico ha raccomandato che con la probabilità bayesiana è possibile "aiutare" la stima di probabilità presentando una "distribuzione di probabilità precedente", essenzialmente si tratta di informazioni su ciò che si prevede di vedere, prima di prendere in considerazione i dati effettivi.

Allora, cosa mi piacerebbe fare è creare un metodo che ha qualcosa di simile firma (Java):

double estimateProbability(double[] priorProbabilities, int buyCount, int noBuyCount); 

priorProbabilities è un array di probabilità che ho visto per i prodotti precedenti, che questo metodo userebbe per creare una distribuzione precedente per questa probabilità. buyCount e noBuyCount sono i dati effettivi specifici di questo prodotto, da cui desidero stimare la probabilità dell'acquisto dell'utente, dati i dati e il preventivo. Questo viene restituito dal metodo come un doppio.

non ho bisogno di una soluzione matematicamente perfetta, solo qualcosa che farà meglio di un uniforme o piatta precedente (es. probabilità = buyCount/(buyCount + noBuyCount)). Poiché sono molto più familiare con il codice sorgente che con la notazione matematica, sarei grato se le persone potessero usare il codice nella loro spiegazione.

+1

problema davvero cool, e credo di conoscere la soluzione bayesiana esatta, ma ancora ci vorrà un po 'per il codice (ti dispiacerebbe pseudocodice eseguibile, fonte AKA Python sono? un po 'arrugginito con Java ... ;-). –

+0

Alex, si - Python o pseudo-python va assolutamente bene! – sanity

+2

non penso che questo sia un problema di programmazione di per sé; è una domanda di matematica teorica avvolta in uno stub di metodo java. –

risposta

2

Ecco il calcolo bayesiano e un esempio/test:

def estimateProbability(priorProbs, buyCount, noBuyCount): 
    # first, estimate the prob that the actual buy/nobuy counts would be observed 
    # given each of the priors (times a constant that's the same in each case and 
    # not worth the effort of computing;-)` 
    condProbs = [p**buyCount * (1.0-p)**noBuyCount for p in priorProbs] 
    # the normalization factor for the above-mentioned neglected constant 
    # can most easily be computed just once 
    normalize = 1.0/sum(condProbs) 
    # so here's the probability for each of the prior (starting from a uniform 
    # metaprior) 
    priorMeta = [normalize * cp for cp in condProbs] 
    # so the result is the sum of prior probs weighed by prior metaprobs 
    return sum(pm * pp for pm, pp in zip(priorMeta, priorProbs)) 

def example(numProspects=4): 
    # the a priori prob of buying was either 0.3 or 0.7, how does it change 
    # depending on how 4 prospects bought or didn't? 
    for bought in range(0, numProspects+1): 
    result = estimateProbability([0.3, 0.7], bought, numProspects-bought) 
    print 'b=%d, p=%.2f' % (bought, result) 

example() 

output è:

b=0, p=0.31 
b=1, p=0.36 
b=2, p=0.50 
b=3, p=0.64 
b=4, p=0.69 

che concorda con il mio per mano di calcolo per questo semplice caso. Si noti che la probabilità di acquisto, per definizione, sarà sempre tra il più basso e il più alto tra le probabilità a priori; se non è quello che vuoi, potresti voler introdurre un po 'di caramelle introducendo due "pseudo-prodotti", uno che nessuno comprerà mai (p = 0.0), uno che comprerà sempre (p = 1.0) - questo dà più peso alle osservazioni reali, per quanto scarso, e meno alle statistiche sui prodotti passati. Se lo facciamo qui, otteniamo:

b=0, p=0.06 
b=1, p=0.36 
b=2, p=0.50 
b=3, p=0.64 
b=4, p=0.94 

livelli intermedi di fudging (per spiegare la possibilità improbabile, ma non impossibile che questo nuovo prodotto può essere peggio di un qualsiasi mai precedentemente venduti, o meglio di qualsiasi di essi) può essere facilmente immaginato (dare un peso inferiore alle probabilità artificiali di 0.0 e 1.0, aggiungendo un vettore precedentePeso agli argomenti di estimateProbability).

Questo genere di cose è una parte sostanziale di quello che faccio tutto il giorno, ora che io lavoro lo sviluppo di applicazioni in Business Intelligence, ma io proprio non può ottenere abbastanza di esso ... -!)

+0

Grazie Alex, sono contento che qualcuno abbia apprezzato la domanda :-) Questo sicuramente sembra giusto ma non potrò esaminare la tua risposta in dettaglio fino a domani. Detto questo, sono felice di accettare la tua risposta per ora :-) – sanity

+0

Controllate tutti i modi (transcodifica in Java secondo necessità, ma considerate Jython per test rapidi e sporchi) e tornate da me, sia su questa domanda o una nuova, sono almeno tanto desideroso di farlo funzionare correttamente! -) * lunga durata Bayes ...! -) * –

0

Sembra che quello che stai cercando di fare è Association Rule Learning. Al momento non ho tempo per fornirti alcun codice, ma ti indicherò nella direzione di WEKA che è un fantastico toolkit di data mining open source per Java. Dovresti trovare molte cose interessanti lì che ti aiuteranno a risolvere il tuo problema.

+0

Questo è interessante, ma non vedo come risolve il problema specifico che descrivo: -/ – sanity

+0

+1 per contrastare l'ignoranza/la pigrizia; questo è un ottimo suggerimento –

+0

Steven, ho letto l'articolo collegato su ARL nella sua interezza. Forse potresti spiegare come questo suggerimento risolve il problema specifico che ho delineato? – sanity

0

Come vedo, il meglio che si possa fare è usare la distribuzione uniforme, a meno che non si abbia qualche idea riguardo la distribuzione. O stai parlando di creare una relazione tra questi prodotti e prodotti precedentemente acquistati dalla stessa persona in Amazon Fashion "chi compra questo prodotto compra anche ..." ??

+0

L'indizio relativo alla distribuzione viene fornito nel parametro priorProbabilities al metodo. Questo è un elenco di probabilità di acquisto che abbiamo trovato per altri prodotti e può essere utilizzato (si spera) per fornire una distribuzione preliminare per la probabilità di acquisto di questo prodotto. – sanity

+0

IMHO, è necessario correlare l'acquisto o meno con qualche altro parametro (ad esempio, età, sesso, paese, ora dell'anno, ora del giorno, altri prodotti acquistati, ecc.). In caso contrario, le migliori informazioni disponibili sono la distribuzione uniforme utilizzando il tasso di acquisto accumulato. – tekBlues

+0

Questo è tutto ciò che sto cercando a questo punto. Normalmente mi piacerebbe correlare con i metadati come età e sesso, ma il problema è che semplicemente non ci sono abbastanza dati per questo. La mia sfida qui è quella di fornire la probabilità più precisa possibile di effettuare un acquisto sulla base di una quantità minima di dati (forse solo poche centinaia di chiamate, dove il tasso di acquisto tipico è intorno al 5-10%). Il partizionamento dei dati in base all'età o al sesso semplicemente non è possibile perché non ci sono abbastanza dati per questo. – sanity

2

A Un modo davvero semplice per fare ciò senza complicare la matematica è aumentare artificialmente buyCount e noBuyCount aggiungendo clienti virtuali acquistati o non acquistati. Puoi sintonizzare quanto credi in ogni particolare probabilità precedente in termini di quanti clienti virtuali pensi che valga.

In pseudocodice:

def estimateProbability(priorProbs, buyCount, noBuyCount, faithInPrior=None): 
    if faithInPrior is None: faithInPrior = [10 for x in buyCount] 
    adjustedBuyCount = [b + p*f for b,p,f in 
           zip(buyCount, priorProbs, faithInPrior] 
    adjustedNoBuyCount = [n + (1-p)*f for n,p,f in 
           zip(noBuyCount, priorProbs, faithInPrior] 
    return [b/(b+n) for b,n in zip(adjustedBuyCount, adjustedNoBuyCount]