2010-11-25 14 views
5

mögliche Dubletten:
Random weighted choice
Generate random numbers with a given (numerical) distributionPython: Auswählen von Zahlen mit zugehörigen Wahrscheinlichkeiten

Ich habe eine Liste der Liste, die eine Reihe an Zahlen enthält und es Wahrscheinlichkeiten zugeordnet.

prob_list = [[1, 0.5], [2, 0.25], [3, 0.05], [4, 0.01], [5, 0.09], [6, 0.1]] 

beispielsweise in prob_list[0] die Nummer 1 hat eine Wahrscheinlichkeit von 0,5 mit ihm verbunden ist. Sie würden also erwarten, dass 1 in 50% der Fälle auftaucht.

Wie füge ich den Zahlen Gewicht bei, wenn ich sie auswähle?

HINWEIS: die Menge der Zahlen in der Liste kann variiert von 6 - 100


EDIT

in der Liste Ich habe 6 Nummern mit den zugehörigen Wahrscheinlichkeiten. Ich möchte zwei Zahlen basierend auf ihrer Wahrscheinlichkeit auswählen.

Keine Nummer kann zweimal ausgewählt werden. Wenn "2" ausgewählt ist, kann es nicht erneut ausgewählt werden.

+0

Mögliche Duplikat http://stackoverflow.com/questions/4265988/generate-random-numbers-with-a-given-numerical-distribution/ – khachik

+0

Versuchen Sie, Zufallszahlen zu erzeugen? Erwartungswert berechnen? – robert

+0

Hallo, ich verstehe die Frage nicht ... Was würdest du gerne mit den Zahlen machen? – SubniC

Antwort

1

Dies könnte das sein, wonach Sie suchen. Erweiterung auf eine Lösung in Generate random numbers with a given (numerical) distribution. Entfernt das ausgewählte Element aus der Verteilung, aktualisiert die Wahrscheinlichkeiten und gibt selected item, updated distribution zurück. Nicht nachweislich zu funktionieren, sollte aber einen guten Eindruck von der Idee geben.

def random_distr(l): 
    assert l # don't accept empty lists 
    r = random.uniform(0, 1) 
    s = 0 
    for i in xrange(len(l)): 
     item, prob = l[i] 
     s += prob 
     if s >= r: 
      l.pop(i) # remove the item from the distribution 
      break 
    else: # Might occur because of floating point inaccuracies 
     l.pop() 
    # update probabilities based on new domain 
    d = 1 - prob 
    for i in xrange(len(l)): 
     l[i][1] /= d 
    return item, l 

dist = [[1, 0.5], [2, 0.25], [3, 0.05], [4, 0.01], [5, 0.09], [6, 0.1]] 
while dist: 
    val, dist = random_distr(dist) 
    print val 
1

Vielleicht hängt das Problem nur mit der Datenstruktur zusammen. Es wäre einfacher, wenn Sie einen Wörterbuch, anstatt eine Liste von Listen haben:

prob_list = { 1:0.5, 2:0.25, 3:0.05, 4:0.01, 5:0.09, 6:0.1} 

Auf diese Weise können Sie das Gewicht erhalten, die die Nummer entspricht:

import random 
number = weight = -1 
while not(number in prob_list): 
    number = random.randint(0, length(prob_list)) 
    weight = prob_list[ number ] 

print(number, weight) 
4

Ich werde das übernehmen Wahrscheinlichkeiten addieren sich alle zu 1. Wenn sie es nicht tun, werden Sie sie entsprechend skalieren müssen, damit sie es tun.

Zuerst eine einheitliche Zufallsvariable [0, 1] mit random.random() erzeugen. Dann passiere die Liste und summiere die Wahrscheinlichkeiten. Wenn die Summe zum ersten Mal die Zufallszahl überschreitet, geben Sie die zugehörige Zahl zurück. Auf diese Weise, wenn der einheitliche Zufallsvariable fällt erzeugt im Bereich (0,5, 0,75] in Ihrem Beispiel wird 2 zurückgegeben werden, damit sie die erforderliche 0,25 Wahrscheinlichkeit des Geben zurückgegeben.

import random 
import sys 
def pick_random(prob_list): 
    r, s = random.random(), 0 
    for num in prob_list: 
    s += num[1] 
    if s >= r: 
     return num[0] 
    print >> sys.stderr, "Error: shouldn't get here" 

Hier ist ein Test es zeigt funktioniert:

import collections 
count = collections.defaultdict(int) 
for i in xrange(10000): 
    count[pick_random(prob_list)] += 1 
for n in count: 
    print n, count[n]/10000.0 

die Ausgänge:

1 0.498 
2 0.25 
3 0.0515 
4 0.0099 
5 0.0899 
6 0.1007 

EDIT: Nur die Bearbeitung in der Frage sah Wenn Sie zwei verschiedene Nummern auswählen möchten, können Sie die oben, bis die sich wiederholen. Die ausgewählte cond-Nummer ist eindeutig. Aber das wird schrecklich langsam sein, wenn eine Zahl sehr hoch ist (z. B. 0.99999999) Wahrscheinlichkeit damit verbunden. In diesem Fall können Sie die erste Zahl aus der Liste entfernen und die Wahrscheinlichkeiten neu skalieren, sodass sie vor der Auswahl der zweiten Zahl zu 1 addiert werden.

3

Hier ist etwas, das scheint zu funktionieren und alle Ihre Spezifikationen zu erfüllen (und subjektiv scheint es ziemlich schnell). Beachten Sie, dass Ihre Einschränkung, dass die zweite Zahl nicht mit der ersten übereinstimmt, die Wahrscheinlichkeiten für die Auswahl ausschaltet. Dieses Problem wird durch den folgenden Code effektiv ignoriert und erzwingt nur die Einschränkung (mit anderen Worten, die Wahrscheinlichkeit, dass die zweite Zahl nicht sein wird, die für jede Nummer in der prob_list angegeben wird).

import random 

prob_list = [[1, 0.5], [2, 0.25], [3, 0.05], [4, 0.01], [5, 0.09], [6, 0.1]] 

# create a list with the running total of the probabilities 
acc = 0.0 
acc_list = [acc] 
for t in prob_list: 
    acc += t[1] 
    acc_list.append(acc) 

TOLERANCE = .000001 
def approx_eq(v1, v2): 
    return abs(v1-v2) <= TOLERANCE 

def within(low, value, high): 
    """ Determine if low >= value <= high (approximately) """ 
    return (value > low or approx_eq(low, value)) and \ 
      (value < high or approx_eq(high, value)) 

def get_selection(): 
    """ Find which weighted interval a random selection falls in """ 
    interval = -1 
    rand = random.random() 
    for i in range(len(acc_list)-1): 
     if within(acc_list[i], rand, acc_list[i+1]): 
      interval = i 
      break 
    if interval == -1: 
     raise AssertionError('no interval for {:.6}'.format(rand)) 
    return interval 

def get_two_different_nums(): 
    sel1 = get_selection() 
    sel2 = sel1 
    while sel2 == sel1: 
     sel2 = get_selection() 
    return prob_list[sel1][0], prob_list[sel2][0] 
Verwandte Themen