Wie zu tun, gewichtete Stichprobe von Kategorien in python
Gegeben eine Liste von Tupeln, wobei jedes Tupel besteht aus einer Wahrscheinlichkeit und eine Sache möchte ich zum Beispiel ein Element entsprechend seiner Wahrscheinlichkeit. Zum Beispiel, geben Sie die Liste [ (.3, 'a'), (.4, 'b'), (.3, 'c')] ich würde gerne auf Probe " b " 40% der Zeit.
Was ist der übliche Weg, dies zu tun, in python?
Habe ich mir angeschaut das random-Modul, das scheint nicht zu haben eine entsprechende Funktion und numpy.zufällig die, obwohl es eine polynomial-Funktion scheint nicht zu die Ergebnisse in eine schöne form für dieses problem. Ich bin im Grunde auf der Suche nach etwas wie mnrnd in matlab.
Vielen Dank.
Danke für die vielen Antworten, so schnell. Um zu klären, ich bin nicht auf der Suche nach Erklärungen, wie zu schreiben, ein sampling-Schema, sondern verwies auf einfache Weise eine Stichprobe aus einer multinomial-Verteilung gegeben sei eine Menge von Objekten und gewichten oder gesagt werden, dass keine solche Funktion existiert in der standard-Bibliothek und so sollte man schreiben, die eigenen.
- Dieses wurde abgedeckt, bevor. Hier ist meine eigene Meinung: stackoverflow.com/questions/3655430/...
- mögliche Duplikate von Eine gewichtete version von random.Wahl
- numpy.random.multniomial IST mnrnd. Genauer gesagt willst du eine Liste wo die Reihenfolge ist nicht wichtig, z.B. [a,a,a,b,b,b,b,c,c,c] oder eine Verteilung mit einer pseudo-zufälligen Reihenfolge.
- Dies nennt man den kategorischen distribution, durch die Art und Weise.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wie genau möchten Sie die Ergebnisse erhalten?
reduce()
-Wahnsinn für eine besser lesbare Liste-comphehension. (Ich bin mir nicht sicher, ob Sie benachrichtigt werden, wenn ich Editiere meinen Beitrag jetzt...)sholte
's Antwort ist viel einfacher ein. Und kann man es verlängern zu handhaben beliebige Elemente sehr einfache Art und Weise (wie gezeigt). Danknumpy.random.multinomial(5, [.3, .3, .4])
- möglicherweise-Rückgabe: array([2, 2, 1]). sholte entspricht das Ergebnis könnte wie folgt Aussehen: array([1, 0, 2, 0, 1]). Ich sehe nicht, wie sich sein code wäre einfacher als das. Wenn Sie kümmern sich um die Bestellung, sein Ergebnis wäre nützlicher, wenn Sie nicht, mir wäre. Jedenfalls, ich habe code, um seinen input, Arbeit in meinem code und bringt das Ergebnis zurück in eine form, die ich dachte, könnte für ihn von nutzen.multinomial
's. Dankwrestling
ist ein guter Weg, es zu setzen. Deins sieht sehr sauber jetzt.Diese könnten tun, was Sie wollen:
sampler
Funktion. Trotz der Komplikation, und vorausgesetzt, man gibt ein sampler, damit man nicht haben, um neu berechnen, die kumulative Summe, +1, da ist effizient für große arrays aufgrund numpy tun binäre Suche.[.3,.4,.3]
sind die GEWICHTE, wie sollen wir, um die Werte mit Ihnen verbunden?sampled
und Werte werdenvals=['a','b','c']
. Dann werden die abgetasteten Werte werden einfachmap(lambda x:vals[x], sampled)
.Da niemand benutzt die numpy.random.Wahl Funktion, hier ist eines, das zu generieren, was Sie brauchen, in einem einzigen, kompakten line:
Gibt es hacks, die Sie tun können, wenn, zum Beispiel, Ihre Wahrscheinlichkeiten passen gut in Prozentsätze, etc.
Zum Beispiel, wenn Sie fein sind die Prozentsätze, die folgenden arbeiten (auf Kosten einer hohen Speicher-overhead):
Aber der "echte" Weg, es zu tun mit beliebigen float-Wahrscheinlichkeiten ist, die Probe aus der kumulativen Verteilung nach bauen. Dies entspricht der Unterteilung der Einheit Intervall [0,1] in 3 Liniensegmente bezeichnet 'a','b' und 'c'; dann ist Kommissionierung einen beliebigen Punkt auf der Einheit Intervall und sehen, welche Strecke es.
Muss man vorsichtig sein, von Methoden, die Werte zurückgeben, auch wenn deren Wahrscheinlichkeit 0 ist. Glücklicherweise funktioniert diese Methode nicht, aber nur, wenn man einfügen könnte
if prob==0: continue
.Für das Protokoll, hier ist der hackish Weg, es zu tun:
Jedoch, wenn Sie don ' T haben die Auflösung Fragen... das ist wohl tatsächlich der Schnellste Weg möglich. =)
[('a',0.2),('b',0.8)]
oder[('b',0.8),('a',0.2)]
. Die alternative wäre, abholen ein zufälliger Reihenfolge und immer benutzen, dass man, auch durch Rücksendung der üblichensample()
generator. Meine bisherige Lösung hat, und es ist mehr Speicher. Es gibt nichts zu gewinnen, es sei denn, Sie können die Vorteile einer Strategie zum Vorsortieren Sie in einige seltsame Fraktale Struktur so, dass die binäre Suche führt zu einer deutlichen speedup für Distributionen mit viele, viele mögliche Werte...[('a',0.2),('b',0.8)]
, aber wenn Sie nennen es das zweite mal, könnte es zurück[('b',0.8),('a',0.2)]
. Eine Analogie vielleicht: angenommen, Sie haben einen großen Eimer (b: 0.8) und ein kleiner Eimer (a: 0.2). Sie werfen Münzen hinein, trifft immer ein, nie verpassen. Wenn Sie ständig bewegen Sie den Eimer (das denken im 1d) - oder-Schalter, sondern - würde sich das auf das Ergebnis des Experiments? Wenn ich jetzt darüber nachdenke, mit der Analogie, würde ich sagen Nein, obwohl 🙂Wie wärs mit der Erstellung 3 "ein", 4 "b" und 3 "c" in eine Liste ein, dann nur nach dem Zufallsprinzip wählen Sie eine. Mit genug Iterationen erhalten Sie die gewünschte Wahrscheinlichkeit.
Ich rechne damit, die polynomial-Funktion ist eine noch relativ einfache Möglichkeit, um Proben von einer Verteilung in zufälliger Reihenfolge. Dies ist nur eine Art
Dem Eingänge wie angegeben
[(.2, 'a'), (.4, 'b'), (.3, 'c')]
und Größe ist die Anzahl der Proben, die Sie benötigen.Ich bin mir nicht sicher, ob dies die pythonic Weise zu tun, was Sie Fragen, aber Sie verwenden könnte
random.sample(['a','a','a','b','b','b','b','c','c','c'],k)
wobei k die Anzahl der Proben, die Sie wollen.
Für eine robuste Methode, halbieren Einheit Intervall in Abschnitte, basierend auf der kumulativen Wahrscheinlichkeit und schöpfen aus der gleichmäßigen Verteilung (0,1) random.random(). In diesem Fall ist der subintervals wäre (0,.3)(.3,.7)(.7,1). Wählen Sie das element basierend auf die subinterval es fällt.
Nur inspiriert von
sholte
's sehr einfache (und richtige) Antwort: ich werde nur zeigen, wie einfach es sein wird zu verlängern, um Griff beliebigen Elementen, wie:Update:
Basierend auf dem feedback von
phant0m
es stellt sich heraus, dass eine noch einfachere Lösung umgesetzt werden kann, basierend aufmultinomial
wie:IMHO haben wir hier eine schöne Zusammenfassung
empirical cdf
undmultinomial
based sampling nachgeben ähnliche Ergebnisse. So, in Zusammenfassung, es abholen eine, die am besten für Ihre Zwecke.Kann dies von marginalen nutzen, aber ich habe es auf diese Weise:
Dies ist ähnlich zu @Essen Antwort.