» »

[Python] Weighted random

[Python] Weighted random

Oxudes ::

Pozdravljeni, imam slovar poln oznak in njihovih verjetnosti, pa bi rad naključno izbral eno glede na verjetnost.

slovar:{
'a': 0.2,
'b': 0.2,
'c': 0.6
}


Do sedaj sem uporabljal sledečo kodo, ki mi pa daje malo nelagoden občutek kar se tiče razporeditve:
def izbira(slo):
	n = random.uniform(0, 1)
	for beseda, verjetnost in slo.iteritems():
		if n < verjetnost:
			break
		n = n - verjetnost
	return beseda


Ima kdo kak predlog kako bi se to še dalo rešit?

mallard ::

Meni se zdi ta koda v redu. Zakaj maš nelagoden občutek?

Da se razumemo, algoritem, ki ga maš, ti ne garantira točne razporeditve 20% - 20% - 60%. Bi to rad dosegel?

jype ::

Ni v redu, ker ima c v resnici samo 0.4 možnosti, b pa ne bo nikoli izbran.

Genetic ::

ce je n==0.3, bo b izbran:
0. n=0.3, beseda='a',verjetnost=0.2
1. n = n-verjetnost == 0.1, beseda='b', verjetnost=0.2
2. n manjse od verjetnost: OK, return beseda

jype ::

Pa res, sem spregledal tisti minus spodaj.

Jaz bi za v povprečju pravilno distribucijo naredu takole:

while True:
  next = random.choice(slovar)
  if slovar[next] > random.random():
    return next

Zgodovina sprememb…

  • spremenilo: jype ()

Oxudes ::

Da, vem da do neke mere tabela deluje, zanima me kako bi se dalo bolj približati točnim verjetnostim (pač, v dejanskem programu imam par sto različnih besed z izračunanimi verjetnostmi). Saj program dela tako kot mora, zanima me kako bi se ga dalo še izboljšati.

Genetic ::

Zakaj pa tvoj nacin ne bi bil tocen?
Ce imas za vsak item v slovarju podano verjetnost, in je suma==1, potem tvoja metoda pravilno poisce pravi item glede na random number.

V tvojem primeru, random n v [0,1):
n v [0, 0.2) : beseda = 'a';
n v [0.2, 0.4) : beseda = 'b';
n v [0.4, 1) : beseda = 'c';

mallard ::

Na hitro skup spacan test, v C++:

#include <ctime>
#include <cstdlib>
#include <map>
#include <string>
#include <iostream>

using namespace std;

map<string, int> prob;

string random_word()
{
    int i = rand() % 100;
    map<string, int>::iterator it = prob.begin();
    while (it != prob.end()) {
        if (i < it->second) return it->first;
        i -= it->second;
        ++it;
    }
}

int main()
{
    srand(time(0));

    prob["kamen"] = 20;
    prob["skarje"] = 20;
    prob["papir"] = 60;

    map<string, int> distr;
    distr["kamen"] = 0;
    distr["skarje"] = 0;
    distr["papir"] = 0;

    int n = 0;
    while (n++ < 1000000) ++distr[random_word()];

    map<string, int>::iterator it = distr.begin();
    for (; it != distr.end(); ++it)
        std::cout << it->first << ": " << it->second
                  << ", " << it->second / 1000000.0 << "%\n";
}


Primer izpisa:

kamen: 200089, 0.200089%
papir: 600510, 0.60051%
skarje: 199401, 0.199401%

Ni dost točno? :)
Pri par sto besedah v slovarju in manjšem številu poskusov bodo odstopanja od verjetnosti seveda večja, kot so pa v zgornjemu primeru. "Naključnost" pač.

Če bi rad mel točno razporeditev, lahko naprimer narediš polje besed, v katerem število posamezne besede ustreza njeni verjetnosti, velikost polja je pa vsota vseh verjetnosti (krat nek mnogokratnik). Polje naključno zmešaš, potem pa vlečeš ven besede eno po eno. Ko prideš do konca polja, ponoviš postopek.

Zgodovina sprememb…

  • spremenilo: mallard ()

Spura ::

jype je izjavil:

Pa res, sem spregledal tisti minus spodaj.

Jaz bi za v povprečju pravilno distribucijo naredu takole:


while True:
next = random.choice(slovar)
if slovar[next] > random.random():
return next

Si naredil matematicni izracun, ki dokazuje pravilnost te metode? Pravilnost se mi zdi dvomljiva.

Tega se lotevate napacno.
Recimo da imamo a=['a'=0.2, 'b'=0.2, 'c'=0.6]
Ce random vrne interval [0,1) potem je pseudokoda naslednja:
sum = 0
r = random()
for entry in a
    sum += entry.value
    if (r < sum) 
        return entry.key

To zagotavlja pravilno enakomerno distribucijo. En met, ne pa vec metov.

Genetic ::

Saj ima Oxudes tudi samo eno generiranje randoma ...

mallard ::

@Spura, v čem se tvoj način razlikuje od tistga, ki ga OP že ima?

jype ::

Jaz si težko predstavljam, da je vsota vseh verjetnosti pri zajetnem slovarju enaka 1.

FrEaKmAn ::



Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Arduino in luči (strani: 1 2 )

Oddelek: Elektrotehnika in elektronika
9812176 (9802) FX6300B
»

Vprašanje v zvezi z rand() funkcijo

Oddelek: Programiranje
495406 (4596) fireice
»

[C++] Naloga seznam

Oddelek: Programiranje
223305 (2580) Matic1911
»

vector::iterator problemi, brisanje podatkov iz vektorja

Oddelek: Programiranje
81135 (986) mn
»

[c] osnove

Oddelek: Programiranje
352538 (1875) fiction

Več podobnih tem