[Python] Creazione albero stocastico solo con dizionari
Daniele Varrazzo
piro a develer.com
Lun 17 Set 2012 14:02:53 CEST
On 2012-09-17 11:11, Antonio Piepoli wrote:
> Salve a tutti,
>
> premetto che questa domanda è molto stupida ma non riesco a trovare
> una
> soluzione.
> Diciamo che ho un vettore la cui lunghezza è già nota a priori. Ogni
> elemento del vettore deve subire una funzione; il punto è che la
> funzione
> cambia sia da elemento ad elemento ed in generare è scelta con una
> certa
> probabilità.
>
> stavo pensando a qualcosa di questo tipo
>
> first_stage = {'match':0.5, 'unmatch':0.5}
> match = ['match_surname','match_name']
> unmatch = ['unmatch_surname','unmatch_name']
>
> match_surname = {'1_error':0.5, '2_error':0.3, 'no_error':0.2}
> match_name = {'1_error':0.5, '2_error':0.3, 'no_error':0.2}
>
> for record in records:
> destiny = choose(first_stage)
> for step in destiny:
> function = choose(step)
> function(record[desiny.index(record)])
Questo "record[desiny.index(record)]", a parte il typo, non ho capito
assolutamente cosa sia. "desiny/destiny" è una lista di due stringhe:
che ci fa quell'index(record)? Cos'è records?
> la funzione choose prende un dizionario fatto in quel modo e mi
> restituisce
> un valore (stringa):
>
> def choose(d):
> index = -1
> keys = d.keys()
> r = random.random()
> while (r > 0):
> r -= d[keys[index]]
> index += 1
> return keys[index]
Questa funzione non mi sembra funzionare come credi: sembra dipendere
dall'ordine delle chiavi, non dal valore associato.
In [30]: vv = [ choose({'1_error':0.5, '2_error':0.3,
'no_error':0.2}) for i in range(10000) ]
In [31]: len(vv)
Out[31]: 10000
In [34]: len([v for v in vv if v == '1_error'])
Out[34]: 2997
In [35]: len([v for v in vv if v == '2_error'])
Out[35]: 2024
In [36]: len([v for v in vv if v == 'no_error'])
Out[36]: 4979
> posso associare a quella stringa una variabile/funzione con quel nome
> ?
> stessa cosa dicasi per i vettori. È una cosa che mi consigliate di
> fare ?
Nota che in Python puoi usare le funzioni direttamente come oggetti.
Puoi scrivere match = [match_surname, match_name], dove prima avevi
definito "def match_surname(arg): ...". E poi usare match[0](record) o
match[1](record) per richiamare una delle due.
Un trucchetto per scegliere un elemento di una lista con una certa
distribuzione potrebbe essere:
def makedist(items, probs, size=100):
"""La funzione è volutamente non documentata e oneliner
per spingerti a pensare cosa fa.
"""
return sum(([i] * int(float(p) / sum(probs) * size) for i, p in
zip(items, probs)), [])
In [61]: dist = makedist(['1_error', '2_error', 'no_error'], [0.5,
0.3, 0.2])
In [62]: vv = [ random.choice(dist) for i in range(10000) ]
In [63]: len([v for v in vv if v == '1_error'])
Out[63]: 5022
In [64]: len([v for v in vv if v == '2_error'])
Out[64]: 3002
In [65]: len([v for v in vv if v == 'no_error'])
Out[65]: 1976
Nota, anche qui, che se serve gli elementi in items possono essere
funzioni, non stringhe. Quindi se hai una famiglia di funzioni f1, f2,
... associate a probabilità p1, p2, ... puoi fare qualcosa tipo.
dist = makedist([f1, f2, ...], [p1, p2, ...])
for record in records:
random.choice(dist)(record)
--
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com
Maggiori informazioni sulla lista
Python