Wie generiere ich Zahlen basierend auf einer beliebigen diskreten Verteilung?

28

Wie erstelle ich Zahlen basierend auf einer beliebigen diskreten Verteilung?

Zum Beispiel habe ich eine Reihe von Zahlen, die ich generieren möchte. Angenommen, sie sind wie folgt mit 1-3 gekennzeichnet.

1: 4%, 2: 50%, 3: 46%

Grundsätzlich handelt es sich bei den Prozentsätzen um Wahrscheinlichkeiten, mit denen sie in der Ausgabe des Zufallszahlengenerators erscheinen. Ich habe einen Pesudorandom-Zahlengenerator, der eine gleichmäßige Verteilung im Intervall [0, 1] erzeugt. Gibt es eine Möglichkeit, dies zu tun?

Es gibt keine Grenzen für die Anzahl der Elemente, die ich haben kann, aber die% summieren sich zu 100%.

FurtiveFelon
quelle
2
Ich könnte vorschlagen, im Titel "... beliebige diskrete Verteilungen" anzugeben, wenn das Ihre Frage ist. Der kontinuierliche Fall ist anders.
David M Kaplan
3
Eine generische Möglichkeit besteht darin, eine binäre Suche innerhalb einer Liste der kumulativen Wahrscheinlichkeiten durchzuführen, die in diesem Beispiel . Im Durchschnitt dauert dies log ( n ) / 2 Sonden pro Generationsereignis. Wenn keine Wahrscheinlichkeit extrem klein ist, können Sie die O ( 1 ) -Leistung erhalten, indem Sie in [ 0 , 1 ] einen Vektor mit gleichen Abständen erstellen und (in einer Vorberechnungsphase) jedem Wert ein Ergebnis zuweisen. In diesem Beispiel können Sie beispielsweise den Vektor ( 1(0,0.04,0.54,1.0)log(n)/2O(1)[0,1] (mit 50 2 und 46 3). Erstellen Sie eine Uniform, multiplizieren Sie sie mit 100 und indexieren Sie diesen Vektor: done. (1,1,1,1,2,,2,3,,3)5046
Whuber
Siehe auch hier
Glen_b -Reinstate Monica
Dieser "hier" -Link verweist tatsächlich auf genau diese Frage, @Glen_b ... Kopieren-und-Einfügen-Fehler?
Buruzaemon
@buruzaemon danke ja das war ein fehler; Ich habe es korrigiert.
Glen_b -Reinstate Monica

Antworten:

26

Einer der besten Algorithmen zum Abtasten aus einer diskreten Verteilung ist die Alias-Methode .

Die Alias-Methode berechnet (effizient) eine zweidimensionale Datenstruktur vor, um ein Rechteck in Bereiche zu unterteilen, die proportional zu den Wahrscheinlichkeiten sind.

Zahl

In diesem schematischen vom referenzierten Seite hat ein Rechteck von Einheitshöhe in vier Arten von Bereichen partitioniert worden - wie durch Farbe unterscheidet - in den Verhältnissen , 1 / 3 , 1 / 12 und 1 / 12 , in um mit diesen Wahrscheinlichkeiten wiederholt aus einer diskreten Verteilung abzutasten. Die vertikalen Streifen haben eine konstante (Einheits-) Breite. Jedes ist in nur ein oder zwei Teile unterteilt. Die Identitäten der Teile und die Positionen der vertikalen Unterteilungen werden in Tabellen gespeichert, auf die über den Spaltenindex zugegriffen werden kann.1/21/31/121/12

Die Tabelle kann in zwei einfachen Schritten abgetastet werden (einer für jede Koordinate), wobei nur zwei unabhängige einheitliche Werte und eine -Berechnung generiert werden müssen. Dies verbessert die O ( log ( n ) ) - Berechnung, die zum Invertieren der diskreten CDF erforderlich ist, wie in anderen Antworten hier beschrieben.O(1)O(log(n))

Lucas
quelle
2
Dieser Algorithmus ist nur dann am besten, wenn die Wahrscheinlichkeiten günstig zu berechnen sind. Wenn beispielsweise groß ist, ist es möglicherweise besser, nicht den gesamten Baum zu konstruieren. n
Wahrscheinlichkeitsrechnung
3
+1 Bisher ist dies die einzige Antwort, die einen effizienten Algorithmus vorschlägt und beschreibt.
whuber
19

Sie können dies einfach in R tun, geben Sie einfach die Größe an, die Sie benötigen:

sample(x=c(1,2,3), size=1000, replace=TRUE, prob=c(.04,.50,.46))
Dominic Comtois
quelle
3
Persönlich würde ich einen Algorithmus bevorzugen (oder irgendwo, um das notwendige Wissen zu erlernen), da ich versuche, dies in eine App zu integrieren, die ich
baue
Hmmm ok ... Ein bisschen mehr darüber zu wissen, was Sie tun möchten, würde uns helfen, Sie anzuleiten. Kannst du uns mehr darüber erzählen? (Zweck, Kontext usw.)
Dominic Comtois
Es ist zur Abstimmung. Ich habe zum Beispiel eine Reihe von Fotos und kann einem Benutzer immer nur 6 zeigen. Ich möchte einem Benutzer immer nur das "Beste" zeigen und der Benutzer kann für jedes Foto nach oben oder unten stimmen . Die einfachste Lösung, die jetzt funktionieren könnte, ist das Schema, das ich skizziert habe (jede Zahl repräsentiert ein Foto, jede Abnahme würde die Wahrscheinlichkeit auf diesem Foto verringern und alles andere erhöhen)
FurtiveFelon
1
@furtivefelon, Sie können den Code immer von R portieren, o den Algorithmus aus dem Code herausfinden und ihn erneut implementieren.
mpiktas
Ich denke, Sie könnten einige gute (bessere) Ratschläge zu Stack Overflow erhalten, da es wahrscheinlich einige bekannte Lösungen für diesen speziellen Zweck gibt. Ich schlage vor, auch die Informationen aus Ihrem letzten Kommentar direkt in Ihre Frage aufzunehmen.
Dominic Comtois
19

Nehmen wir in Ihrem Beispiel an, Sie zeichnen Ihren pseudozufälligen Uniform-Wert [0,1] und nennen ihn U. Dann geben Sie Folgendes aus:

1, wenn U <0,04

2 wenn U> = 0,04 und U <0,54

3 wenn U> = 0,54

Wenn die angegebenen% a, b, ... sind, einfach ausgeben

Wert 1, wenn U

Wert 2, wenn U> = a und U <(a + b)

etc.

Im Wesentlichen bilden wir das% in Teilmengen von [0,1] ab, und wir wissen, dass die Wahrscheinlichkeit, dass ein einheitlicher Zufallswert in einen beliebigen Bereich fällt, einfach die Länge dieses Bereichs ist. Das Ordnen der Bereiche scheint die einfachste, wenn nicht die einzige Möglichkeit zu sein. Dies setzt voraus, dass Sie nur nach diskreten Verteilungen fragen. für Dauerbetrieb kann man so etwas wie "Rejection Sampling" machen ( Wikipedia-Eintrag ).

David M Kaplan
quelle
8
Der Algorithmus ist schneller, wenn Sie die Kategorien in absteigender Reihenfolge der Wahrscheinlichkeit sortieren. Auf diese Weise führen Sie (im Durchschnitt) weniger Tests pro generierter Zufallszahl durch.
Jbowman
1
pjDistPr(Y=j)=pjO(nlog(n))Zeit für jede Iteration. In diesem Fall kann es jedoch nützlich sein, nach einer ungefähren Schätzung der Größe der Wahrscheinlichkeiten zu Beginn zu sortieren.
Wahrscheinlichkeitsrechnung
4

m[0,1]F(0,1)

I1I2Im

Ij=(F(j1),F(j))F(0)0m=3

I1=(0,.04),     I2=(.04,.54),     I3=(.54,1)

F(1)=.04F(2)=.54F(3)=1

XF

UUniform(0,1)

UIjX=j

  • UTRUEFALSEFALSE

UIj[0,1]

Makro
quelle
{[0,0.04), [0.04,0.54), [0.54,1]}
1
P(U=u)=0u
1
Auf einer digitalen Maschine mit endlicher Präzision wird es jedoch vielleicht eines Tages vor dem Ende des Universums darauf
ankommen
1
Fair genug, @whuber, siehe meine Bearbeitung.
Makro
1
OK, das ist ein Algorithmus. Übrigens, warum geben Sie nicht einfach so etwas zurück min(which(u < cp))? Es wäre gut zu vermeiden, die kumulierte Summe auch bei jedem Anruf neu zu berechnen. Mit dieser Vorberechnung wird der gesamte Algorithmus auf reduziert min(which(runif(1) < cp)). Oder besser, weil das OP fordert, Zahlen ( Plural ) zu generieren , vektorisieren Sie es als n<-10; apply(matrix(runif(n),1), 2, function(u) min(which(u < cp))).
whuber
2

Ein einfacher Algorithmus besteht darin, mit Ihrer einheitlichen Zufallszahl zu beginnen und in einer Schleife zuerst die erste Wahrscheinlichkeit abzuziehen. Wenn das Ergebnis negativ ist, geben Sie den ersten Wert zurück, wenn es immer noch positiv ist, gehen Sie zur nächsten Iteration und subtrahieren die nächste Wahrscheinlichkeit , prüfe ob negativ usw.

Das ist insofern schön, als die Anzahl der Werte / Wahrscheinlichkeiten unendlich sein kann, aber Sie müssen die Wahrscheinlichkeiten nur berechnen, wenn Sie sich diesen Zahlen nähern (zum Beispiel wenn Sie aus einer Poisson-Verteilung oder einer negativen Binomialverteilung generieren).

Wenn Sie eine endliche Menge von Wahrscheinlichkeiten haben, aber viele Zahlen daraus generieren, ist es möglicherweise effizienter, die Wahrscheinlichkeiten so zu sortieren, dass Sie zuerst die größte, dann die zweitgrößte subtrahieren und so weiter.

Greg Snow
quelle
2

Lassen Sie mich zunächst Ihre Aufmerksamkeit auf eine Python-Bibliothek mit gebrauchsfertigen Klassen für die Generierung von Ganzzahl- oder Gleitkommazahlen lenken, die einer beliebigen Verteilung folgen.

Generell gibt es verschiedene Ansätze für dieses Problem. Einige sind zeitlich linear, erfordern jedoch einen großen Speicher, andere werden in der Zeit 0 (n log (n)) ausgeführt. Einige sind für ganzzahlige Zahlen optimiert, andere für kreisförmige Histogramme (zum Beispiel: Erzeugen zufälliger Zeitpunkte während eines Tages). In der oben genannten Bibliothek habe ich dieses Papier für Ganzzahlfälle und dieses Rezept für Gleitkommazahlen verwendet. Es fehlt (noch) die Unterstützung für kreisförmige Histogramme und es ist im Allgemeinen chaotisch, aber es funktioniert gut.

Boris Gorelik
quelle
2

Ich hatte das gleiche problem Bei einer Menge, bei der jedes Element eine Wahrscheinlichkeit hat und deren Wahrscheinlichkeit eins ergibt, wollte ich eine Stichprobe effizient zeichnen, dh ohne etwas zu sortieren und ohne die Menge wiederholt zu durchlaufen .

N[a,1)r[0,1)

next(N,a)=1(1a)rN

(ai)NN=10

a0=next(10,0)
a1=next(9,a0)
a2=next(8,a1)

a9=next(1,a8)

(ai)P0k<|P|pkPaikp0pk>aipkai+1


{(1,0.04),(2,0.5),(3,0.46)}N=10

i a_i k Sum Draw
0 0,031 0 0,04 1
1 0,200 1 0,54 2
2 0,236 1 0,54 2
3 0.402 1 0.54 2
4 0,488 1 0,54 2
5 0,589 2 1,0 3
6 0,625 2 1,0 3
7 0,638 2 1,0 3
8 0,738 2 1,0 3
9 0,942 2 1,0 3

(1,2,2,2,2,3,3,3,3,3)


nextN[a,x)x1

casi
quelle
Es scheint, dass sich das Problem, das Sie ansprechen, im zweiten Absatz abrupt von einem Stichprobenverfahren aus einer beliebigen diskreten Verteilung zu einem Stichprobenverfahren aus einer gleichmäßigen Verteilung geändert hat . Ihre Lösung scheint für die hier gestellte Frage nicht relevant zu sein.
Whuber
Ich habe den letzten Teil geklärt.
Casi
{1,2,3}
Ich habe ein Beispiel hinzugefügt. Meine Antwort hat etwas mit der Antwort von David M Kaplan ( stats.stackexchange.com/a/26860/93386 ) zu tun , erfordert jedoch nur eine Iteration anstelle von N (= Stichprobengröße) über die Menge, auf Kosten der Zeichnung von N N- th Wurzeln. Ich habe beide Prozeduren analysiert und meine war viel schneller.
Casi
aj=i=1jlog(ui)i=1N+1log(ui)
u1,,uN+1