Ich habe zum Beispiel diesen Tisch
+ ----------------- + | Obst | gewicht | + ----------------- + | Apfel | 4 | | orange | 2 | | Zitrone | 1 | + ----------------- +
Ich muss eine zufällige Frucht zurückgeben. Aber Apfel sollte 4-mal so häufig wie Zitrone und 2-mal so häufig wie Orange gepflückt werden .
Im allgemeineren Fall sollte es f(weight)
mal häufig sein.
Was ist ein guter allgemeiner Algorithmus, um dieses Verhalten zu implementieren?
Oder gibt es vielleicht einige fertige Edelsteine auf Ruby? :)
PS
Ich habe den aktuellen Algorithmus in Ruby https://github.com/fl00r/pickup implementiert
algorithms
ruby
math
random
fl00r
quelle
quelle
Antworten:
Die konzeptionell einfachste Lösung wäre, eine Liste zu erstellen, in der jedes Element so oft vorkommt, wie es gewichtet ist
Verwenden Sie dann die Funktionen, die Ihnen zur Verfügung stehen, um ein zufälliges Element aus dieser Liste auszuwählen (z. B. einen zufälligen Index im richtigen Bereich erstellen). Dies ist natürlich nicht sehr speichereffizient und erfordert ganzzahlige Gewichte.
Ein anderer, etwas komplizierterer Ansatz würde so aussehen:
Berechnen Sie die kumulativen Summen der Gewichte:
Wenn ein Index unter 4 einen Apfel darstellt , 4 bis unter 6 eine Orange und 6 bis unter 7 eine Zitrone .
Generieren Sie eine Zufallszahl
n
im Bereich von0
bissum(weights)
.n
. Die entsprechende Frucht ist Ihr Ergebnis.Dieser Ansatz erfordert komplizierteren Code als der erste, aber weniger Speicher und Berechnung und unterstützt Gleitkommagewichte.
Für jeden Algorithmus kann der Einrichtungsschritt einmal für eine beliebige Anzahl von Zufallsauswahlen durchgeführt werden.
quelle
Hier ist ein Algorithmus (in C #), mit dem zufällig gewichtetes Element aus einer beliebigen Sequenz ausgewählt und nur einmal durchlaufen werden kann:
Dies basiert auf der folgenden Überlegung: Wählen wir das erste Element unserer Sequenz als "aktuelles Ergebnis" aus; Behalten Sie es dann bei jeder Iteration bei oder verwerfen Sie es und wählen Sie ein neues Element als aktuell aus. Wir können die Wahrscheinlichkeit berechnen, dass ein bestimmtes Element am Ende als Produkt aller Wahrscheinlichkeiten ausgewählt wird, dass es in nachfolgenden Schritten nicht verworfen wird, mal die Wahrscheinlichkeit, dass es überhaupt ausgewählt wird. Wenn Sie rechnen, werden Sie feststellen, dass sich dieses Produkt auf (Gewicht des Elements) / (Summe aller Gewichte) vereinfacht, was genau das ist, was wir brauchen!
Da diese Methode die Eingabesequenz nur einmal durchläuft, funktioniert sie auch bei übermäßig großen Sequenzen, vorausgesetzt, die Summe der Gewichte passt in eine
int
(oder Sie können einen größeren Typ für diesen Zähler auswählen).quelle
Bereits vorliegende Antworten sind gut und ich werde sie ein wenig erweitern.
Wie Benjamin vorschlug, werden bei dieser Art von Problem normalerweise kumulative Summen verwendet:
Um ein Element in dieser Struktur zu finden, können Sie einen Code wie Nevermind verwenden. Dieses Stück C # -Code, das ich normalerweise verwende:
Nun zum interessanten Teil. Wie effizient ist dieser Ansatz und welche Lösung ist am effizientesten? Mein Code benötigt O (n) Speicher und wird in O (n) Zeit ausgeführt. Ich glaube nicht, dass dies mit weniger als O (n) Raum getan werden kann, aber die zeitliche Komplexität kann viel geringer sein, O (log n) in der Tat. Der Trick besteht darin, eine binäre Suche anstelle einer regulären for-Schleife zu verwenden.
Es gibt auch eine Geschichte über das Aktualisieren von Gewichten. Im schlimmsten Fall bewirkt die Aktualisierung der Gewichtung für ein Element die Aktualisierung der kumulativen Summen für alle Elemente, wodurch die Aktualisierungskomplexität auf O (n) erhöht wird . Auch das kann mithilfe eines binär indizierten Baums auf O (log n) reduziert werden .
quelle
Dies ist eine einfache Python-Implementierung:
und
In genetischen Algorithmen wird dieses Auswahlverfahren als Fitness-Proportional-Auswahl oder Roulette-Rad-Auswahl bezeichnet, da:
Typische Algorithmen haben die Komplexität O (N) oder O (log N), aber Sie können auch O (1) ausführen (z. B. Roulette-Rad-Auswahl über stochastische Akzeptanz ).
quelle
Dieser Kern tut genau das, wonach Sie fragen.
du kannst es so benutzen:
Der obige Code wird höchstwahrscheinlich (% 98) 0 zurückgeben, was der Index für 'apple' für das angegebene Array ist.
Außerdem testet dieser Code die oben bereitgestellte Methode:
Es gibt eine Ausgabe in etwa so:
quelle