Gegeben ein Array von n
Wort-Frequenz Paaren:
Dabei ist wi
ein Wort, fi
ist eine ganze Zahl und die Summe der Häufigkeiten ∑fi = m
,
Ich möchte einen Pseudozufallszahlengenerator (pRNG) verwenden, um p
words wj0, wj1, ..., wjp-1
so auszuwählen, dass
Die Wahrscheinlichkeit, ein Wort auszuwählen, ist proportional zu seiner Häufigkeit:
(Bitte beachten Sie, dass es sich um eine Auswahl mit Ersatz handelt, daher kann jedes Mal das gleiche Wort gewählt werden.)
Ich habe bis jetzt drei Algorithmen entwickelt:
Erstellen Sie ein Array der Größe m
, und füllen Sie es so, dass die ersten f0
-Einträge w0
, die nächsten f1
-Einträge w1
usw. sind, also die letzten fp-1
-Einträge wp-1
.
p
-Indizes im Bereich 0...m-1
auszuwählen, und melden Sie die in diesen Indizes gespeicherten Wörter. O(n + m + p)
work, was nicht großartig ist, da m
viel viel größer sein kann als n. Gehen Sie einmal durch das Eingabe-Array und berechnen Sie
%Vor% und nach Berechnung vonmi
, benutze den pRNG, um eine Zahl xk
im Bereich 0...mi-1
für jede k
in 0...p-1
zu generieren
und wählen Sie wi
für wjk
(möglicherweise ersetzt den aktuellen Wert von wjk
) wenn xk < fi
. O(n + np)
work. mi
wie in Algorithmus 2 und erzeuge das folgende Array auf n Wort-Frequenz-Partialsummen-Tripeln: [ (w0, f0), (w1, f1), ..., (wn-1, fn-1) ]und dann, für jedes k in
0...p-1
, benutze das pRNG, um eine Zahl xk
im Bereich 0...m-1
zu erzeugen, dann führe eine binäre Suche auf dem Tripelfeld durch, um die i
s.t. mi-fi ≤ xk < mi
, und wählen Sie wi
für wjk
. O(n + p log n)
work. Meine Frage ist : Gibt es einen effizienteren Algorithmus, den ich dafür verwenden kann, oder sind diese so gut wie es geht?
Ok, ich habe einen anderen Algorithmus gefunden: die Alias-Methode (auch erwähnt < a href="https://stackoverflow.com/questions/352670/weighted-random-selection-with-and-without-replacement/353576#353576"> in dieser Antwort ). Im Grunde erstellt es eine Partition des Wahrscheinlichkeitsraums, so dass:
n
Partitionen, die alle die gleiche Breite r
s.t. nr = m
. wi
, fi = ∑partitions t s.t wi ∈ t r × ratio(t,wi)
Da alle Partitionen dieselbe Größe haben, wählen Sie, welche Partition in konstanter Arbeit ausgeführt werden kann (wählen Sie zufällig einen Index von 0...n-1
), und das Partitionsverhältnis kann dann verwendet werden, um auszuwählen, welches Wort in konstant verwendet wird arbeiten (vergleiche eine pRNGed-Zahl mit dem Verhältnis zwischen den beiden Wörtern). Das bedeutet, dass die p
-Auswahl in O(p)
work bei einer solchen Partition erfolgen kann.
Der Grund dafür, dass eine solche Partitionierung existiert, besteht darin, dass ein Wort wi
s.t. fi < r
, wenn und nur wenn ein Wort wi'
s.t. fi' > r
, da r der Durchschnitt der Frequenzen ist.
Bei einem solchen Paar wi
und wi'
können wir sie durch ein Pseudowort w'i
der Häufigkeit f'i = r
ersetzen (das wi
mit der Wahrscheinlichkeit fi/r
und wi'
mit der Wahrscheinlichkeit% co_de darstellt %) und ein neues Wort 1 - fi/r
der angepassten Häufigkeit w'i'
. Die durchschnittliche Häufigkeit aller Wörter ist immer noch r, und die Regel aus dem vorherigen Absatz gilt immer noch. Da das Pseudowort die Frequenz r hat und aus zwei Wörtern mit der Häufigkeit r besteht, wissen wir, dass wir, wenn wir diesen Prozess iterieren, niemals ein Pseudowort aus einem Pseudowort erzeugen werden, und diese Iteration muss mit a enden Sequenz von n Pseudowörtern, die die gewünschte Partition sind.
Um diese Partition in f'i' = fi' - (r - fi)
time zu erstellen,
Das funktioniert auch noch, wenn die Anzahl der Partitionen O(n)
ist (du musst es nur anders beweisen). Wenn Sie sicherstellen wollen, dass r integral ist und Sie nicht einfach einen Faktor q > n
von q
s.t. m
, Sie können alle Frequenzen mit einem Faktor von q > n
auffüllen, also n
, wodurch f'i = nfi
aktualisiert und m' = mn
bei r' = m
festgelegt wird.
In jedem Fall braucht dieser Algorithmus nur q = n
work, was ich für optimal halte.
In Ruby:
%Vor%Das klingt wie eine Rouletteradauswahl, die hauptsächlich für den Auswahlprozess in genetischen / evolutionären Algorithmen verwendet wird.
Sehen Sie sich Roulette-Auswahl in genetischen Algorithmen
anSie könnten das Zielarray erstellen, dann die Wörter durchgehen, die die Wahrscheinlichkeit bestimmen, dass es ausgewählt werden soll, und die Wörter im Array nach einer Zufallszahl ersetzen.
Für das erste Wort würde die Wahrscheinlichkeit f 0 / m <0 sein (wobei mn = f0 ) > + .. + f n ), dh 100%, so dass alle Positionen im Zielarray mit w 0 gefüllt würden.
Für die folgenden Wörter fällt die Wahrscheinlichkeit, und wenn Sie das letzte Wort erreichen, wird das Zielfeld mit zufällig ausgewählten Wörtern entsprechend der Häufigkeit gefüllt.
Beispielcode in C #:
%Vor%