[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