Häufigkeitsverteilung von Zufallszahlen manipulieren
oliver
- php
0 mipu0 Christoph Zurnieden0 Sven Rautenberg0 oliver
0 Carsten0 oliver
und erst dachte ich es wäre ganz einfach...
Ich bastel grade an einer Funktion die eine Zufallszahl (int) innerhalb
eines vorgegebenen Zahlenranges zurückgeben soll.
Als weiterer Parameter wird ein Durchschnittswert übergeben - die zurückgegebene Zufallszahl soll also durchschnittlich diesem übergebenen Wert entsprechen.
Beispiel:
function getRandBetweenMinMaxWithAverage($min, $max, $avg){
//do something
return $randval;
}
$randval = getRandBetweenMinMaxWithAverage(0, 3, 0.5);
Wie kann ich jetzt berechnen, wie häufig die einzelnen Werte vorkommen müssen damit der Durchschnittswert 0.5 erreicht wird?
Mir fehlt da irgendwie der Ansatz um das ausrechnen zu können.
Dank euch vielmals für jede Idee!
gruss oliver
Hallo Oliver,
soweit ich mich an meine schon lange zurückliegenden Statistikvorlesungen erinnern kann, setzt die Verwendung eines Mittelwertes immer ein sogenannte "Normalverteilung" der Daten voraus.
Wenn du nach diesem Begriff ein bißchen stöberst, könntest du einer Lösung näherkommen.
gruß mipu
soweit ich mich an meine schon lange zurückliegenden
Statistikvorlesungen erinnern kann, setzt die Verwendung eines
Mittelwertes immer ein sogenannte "Normalverteilung" der Daten voraus.
Klar, wenn ich eine Zufallszahl zwischen 2 und 4 habe, wird diese wegen der
gleichmässigen Verteilung der Zufallszahlen im Durchschnitt 3 sein.
Eben diese Normalverteilung muss ich ja ändern um einen anderen Durchschnittswert
zu erreichen.
Leider hab ich von Statistik keinen Plan, daher meine Frage ;)
gruss oliver
Hm, also imho hilft da der Begriff Standardabweichung weiter.
Bei einer normalverteilten Menge von Zahlen/Stichprobe liegen dann soundsoviel der Zahlen in einem bestimmten Bereich um den Mittelwert.
Also musst du definieren, wie weit die Streuung um den Mittelwert reichen darf, und prüfst dann den erzeugten Wert daraufhin.
http://de.wikipedia.org/wiki/Standardabweichung
min und Max kannst du ja schon in der php-funktion benutzen :
int rand ( [ int min [, int max]])
gruß mipu
Hm, also imho hilft da der Begriff Standardabweichung weiter.
Bei einer normalverteilten Menge von Zahlen/Stichprobe liegen dann soundsoviel der Zahlen in einem bestimmten Bereich um den Mittelwert.
Also musst du definieren, wie weit die Streuung um den Mittelwert reichen darf, und prüfst dann den erzeugten Wert daraufhin.
Dank Dir nochmals!
Das der Begriff Standardabweichung in diesem Kontext irgendwas zu suchen hat, leuchtet mir ein, leider steige ich aber bei etwas wie diesem aus, meine Mathekenntnisse rechen einfach nicht um damit was anfangen zu können, das ist mein Problem
http://de.wikipedia.org/math/005ac37b5dfceeabb9c542979a9051b6.png
gruss oliver
Dank Dir nochmals!
Das der Begriff Standardabweichung in diesem Kontext irgendwas zu suchen hat, leuchtet mir ein, leider steige ich aber bei etwas wie diesem aus, meine Mathekenntnisse rechen einfach nicht um damit was anfangen zu können, das ist mein Problem
Tja, ohne Einstieg in die Statistik wird es da wohl nicht gehen :)
Evtl. hilft dir ja auch dieser Thread weiter :
gruß mipu
nochmals Danke, leider wenig hilfreich.
ich wollte eben _keinen_ Statistikkurs absolvieren, das ist der Grund dafür das ich diese Frage hier im Forum stelle...
gruss oliver
Hi,
bitte folge erst dem oben angegebenem Link und beschwere Dich dann.
so short
Christoph Zurnieden
Hi,
und erst dachte ich es wäre ganz einfach...
Ja, so dachten viele ;-)
function getRandBetweenMinMaxWithAverage($min, $max, $avg){
//do something
return $randval;
}$randval = getRandBetweenMinMaxWithAverage(0, 3, 0.5);
Wie kann ich jetzt berechnen, wie häufig die einzelnen Werte vorkommen müssen damit der Durchschnittswert 0.5 erreicht wird?
Mir fehlt da irgendwie der Ansatz um das ausrechnen zu können.
Eienn guten Zufallsgenerator zu bauen ist _sehr_ schwierig!
Aber das ist kein wirkliches Problem. Ich habe zwar auf Anhieb nichts für PHP in dieser Richtung gefunden, aber für C++ gibt es hier etwas http://www.agner.org/random/ (Etwas weiter inten sind auch noch ein paar PDFs, die die Sache etwas weiter erläutern.) und hier in C http://statistik.wu-wien.ac.at/unuran/ sowie natürlich in jedem gutem Statistikprogramm wie z.B. S oder R (Tut mir leid, aber die heißen wirklich so ;). Die eigentlichen und ursprünglichen Fortranimplementationen habe ich jetzt einmal außen vor gelassen. Ich glaube, das war ganz in Deinem Sinne, oder? ;-)
so short
Christoph Zurnieden
Eienn guten Zufallsgenerator zu bauen ist _sehr_ schwierig!
Aber das ist kein wirkliches Problem. Ich habe zwar auf Anhieb nichts für PHP in dieser Richtung gefunden, aber für C++ gibt es hier etwas http://www.agner.org/random/ (Etwas weiter inten sind auch noch ein paar PDFs, die die Sache etwas weiter erläutern.) und hier in C http://statistik.wu-wien.ac.at/unuran/ sowie natürlich in jedem gutem Statistikprogramm wie z.B. S oder R (Tut mir leid, aber die heißen wirklich so ;). Die eigentlichen und ursprünglichen Fortranimplementationen habe ich jetzt einmal außen vor gelassen. Ich glaube, das war ganz in Deinem Sinne, oder? ;-)
äh, jum, öh, vielen Dank für die Infos erstmal, einen eigenen Zufallsgenerator wollte ich aber eigentlich _nicht_ basteln ;)
Es geht mir nur darum auszurechnen, wie oft die einzelnen Werte vorkommen müssen um den angegebenen Durchschnitt zu erreichen, z.B.
bei getRandBetweenMinMaxWithAverage(0, 3, 0.5) würde ich dann wissen
das auf eine 3 x zweien, y einsen und z nullen kommen müssen um auf den Schnitt von 0.5 zu kommen.
Anschliessend würde ich die Summe von 1+x+y+z nehmen und mir mittels der php-standardfunktion srand() einen floatwert zwischen null und dieser Summe geben lassen.
Als letzten Schritt addiere ich dann solange immer den nächsten Wert auf
(1+x+y+z) bis die Summe grösser als die Zufallszahl ist - wenn dies etwa bei 1+x+y der Fall ist, dann lasse ich die Funktion 2 returnen (weil zweitletstes Element zwischen min & max) - so ungefähr dachte ich mir das.
gruss oliver
Hi,
äh, jum, öh, vielen Dank für die Infos erstmal, einen eigenen Zufallsgenerator wollte ich aber eigentlich _nicht_ basteln ;)
Wäre aber ein gute Übung.
Es geht mir nur darum auszurechnen, wie oft die einzelnen Werte vorkommen müssen um den angegebenen Durchschnitt zu erreichen,
Auf die Gefahr hin mich zu wiederholen:
[...] http://www.agner.org/random/ (Etwas weiter unten sind auch noch ein paar PDFs, die die Sache etwas weiter erläutern.) [...]
z.B.
bei getRandBetweenMinMaxWithAverage(0, 3, 0.5) würde ich dann wissen
das auf eine 3 x zweien, y einsen und z nullen kommen müssen um auf den Schnitt von 0.5 zu kommen.
Aaaah, Du brauchst Integerwerte?
Nein, das macht die Sache auch nicht einfacher ;-)
Ich nehme an, es soll das arithmetische Mittel sein?
Dann hast Du bei Deinem Beispiel
0,5 = \frac{3v + 2x + 1y + 0z}{c} für c = |v| + |x| + |y| + |z| und |v| = 1
So, und hier suchst Du jetzt die Minima und nimmst das erstbeste. Dürfte abseits aller mathematischen Theorie die simpelste Methode zur Implementierung sein.
Bitet beachte aber auch die Tücken der Fließkommaberechnung!
Anschliessend würde ich die Summe von 1+x+y+z nehmen und mir mittels der php-standardfunktion srand() einen floatwert zwischen null und dieser Summe geben lassen.
Also doch keine Integerwerte?
Als letzten Schritt addiere ich dann solange immer den nächsten Wert auf
(1+x+y+z) bis die Summe grösser als die Zufallszahl ist - wenn dies etwa bei 1+x+y der Fall ist, dann lasse ich die Funktion 2 returnen (weil zweitletstes Element zwischen min & max) - so ungefähr dachte ich mir das.
Das würde bei einem Großteil der Eingaben nicht beenden.
Ich würde aber nichtsdestotrotz eine kleinen Statistikkurs empfehlen. Grundkenntnisse reichen schon.
so short
Christoph Zurnieden
nochmals Danke, leider wenig hilfreich.
ich wollte eben _keinen_ Statistikkurs absolvieren, das ist der Grund dafür das ich diese Frage hier im Forum stelle...
gruss oliver
Hi,
nochmals Danke, leider wenig hilfreich.
Fertigen Code bekommst Du hier nur sehr selten und doch habe ich das getan. War halt nur nicht direkt in PHP.
ich wollte eben _keinen_ Statistikkurs absolvieren, das ist der Grund dafür das ich diese Frage hier im Forum stelle...
Es gibt eine kleinen aber wichtigen Bereich beim Programmieren, den nenne ich gerne "hohe Kunst". Darunter fallen so Sachen wie sortieren, suchen und Kryptographie. Im Bereich Kryptographie gibt es das Problem, das ein deterministischer Algorithmus statistisch zufällige Ergebnisse zeitigen soll. Zufallsgeneratoren also. Das fängt bei den simpelsten linearen Kongruenzgeneratoren an, geht über sowas wie den Mersenne Twister bis hin zu ausgefeilten Mischmethoden. Da werden zwar möglichst uniforme Ergebnisse benötigt, aber auch für nicht uniforme Ausgaben ist der Grad an Komplexität gleich und zwar hoch. All das, was ich so gerne mit hoher Kunst des Programmierens bezeichnen ist hochmathematisch und nicht einfach.
Die uniforme Verteilung eines guten Zufallsgenerators zu verbiegen ist dagegen recht einfach, benötigt aber, wenn schon keine Statistik, so doch zumindest Grundkenntnisse der Kurvendiskussion, um zu wissen, wie man so eine Kurve verbiegt.
Einen kleine Tip habe ich noch, auch wenn es aussieht, als ob Du gar keine Lust hast selber zu denken:
Aus den drei Punkten kann man nach Bezier eine hübsche Kurve zeichnen. Diese Kurve kannst Du als Filter für die Ausgabe des Zufallsgenerators nutzen.
Natürlich geht es auch mit FFT, aber das fände ich persönlich reichlich übertrieben.
so short
Christoph Zurnieden
Moin!
und erst dachte ich es wäre ganz einfach...
Ist es nicht.
Wie kann ich jetzt berechnen, wie häufig die einzelnen Werte vorkommen müssen damit der Durchschnittswert 0.5 erreicht wird?
Deine gegebenen Informationen und Parameter reichen zur Lösung dieses Problems nicht aus.
Ein Beispiel: Du willst die drei Zufallzahlen 1, 2 und 3 haben, mit dem Mittelwert 2.
Die normale Random-Funktion liefert dir diese drei Zahlen mit gleicher Wahrscheinlichkeit:
1: 33% 2: 33% 3: 33% Und der Mittelwert ist zwei.
Aber genau dieselben Bedingungen (Zahlen von 1 bis 3, Mittelwert 2) werden ja auch bei dieser Verteilung erreicht:
1: 45% 2: 10% 3: 45% Mittelwert immer noch 2.
Anders herum geht es natürlich auch:
1: 5% 2: 90% 3: 5% Mittelwert auch 2.
Es gibt also bei dieser Konstellation unendlich viele Zufallsverteilungen, deren einzige Gemeinsamkeit ist, dass sich die Wahrscheinlichkeit symmetrisch über die drei Werte verteilt (habe ich jetzt mal so mathematisch überschlagen - kann sein, dass auch diese Annahme falsch ist, dann hast du komplett mit Zitronen gehandelt).
Es wird also eine irgendwie geartete Funktion benötigt, die sozusagen "modelliert", welche Wahrscheinlichkeitsverteilungdenn nun rauskommen soll. Alleine der Mittelwert ist jedenfalls nicht aussagekräftig genug.
Und ich habe so das dumme Gefühl, dass da auf dich ganz böse Differentialgleichungen lauern könnten.
- Sven Rautenberg
und erst dachte ich es wäre ganz einfach...
Ist es nicht.
ich fang an das zu glauben, das es nicht einfach ist ;)
Ein Beispiel: Du willst die drei Zufallzahlen 1, 2 und 3 haben, mit dem Mittelwert 2.
Die normale Random-Funktion liefert dir diese drei Zahlen mit gleicher Wahrscheinlichkeit:
1: 33% 2: 33% 3: 33% Und der Mittelwert ist zwei.
soweit klar, die zufallszahlen sind gleichverteilt.
Aber genau dieselben Bedingungen (Zahlen von 1 bis 3, Mittelwert 2) werden ja auch bei dieser Verteilung erreicht:
1: 45% 2: 10% 3: 45% Mittelwert immer noch 2.Anders herum geht es natürlich auch:
1: 5% 2: 90% 3: 5% Mittelwert auch 2.
ok, bloss das bei deinem beispiel der soll-mittelwert von vornherein gegeben ist und daher an der verteilung nix geschraubt werden muss.
wenn wir aber min=0, max=3 und avg=0.5 nehmen, ist auf jeden fall schonmal klar, das die niedrigeren zahlen x mal häufiger als die höheren vorkommen müssen.
dabei will ich von der gleichverteilung möglichst wenig abweichen, also die verteilung sollte soweit möglich linear sein, d.h. bei drei werten a,b,c sollte, wenn von der häufigkeitsverteilung her auf ein a 3c kommen, entsprechend 2b je ein a vorkommen.
bei diesen vorgaben sollten die parameter min, max und avg eigentlich ausreichen.
Und ich habe so das dumme Gefühl, dass da auf dich ganz böse Differentialgleichungen lauern könnten.
urks, ich fürchtete sowas...
gruss oliver
Hi oliver,
Wie kann ich jetzt berechnen, wie häufig die einzelnen Werte vorkommen müssen damit der Durchschnittswert 0.5 erreicht wird?
Mir fehlt da irgendwie der Ansatz um das ausrechnen zu können.
Glauben wir doch einfach mal das es so eine Funktion gibt und testen die dann.
n0=n1=n2=n3=0;
for(i=0;i<GanzViel;i++)
{
z=oli_rand(0,3,0.5);
switch(z)
{
case 0: n0++; break;
case 1: n1++; break;
case 2: n2++; break;
case 3: n3++; break;
}
}
Der Mittelwert berechnet sich dann zu:
n1 * 1 + n2 * 2 + n3 * 3
------------------------ = avg
n0 + n1 + n2 + n3
...kurz wirken lassen...
so nun ist aber n0+n1+n2+n3=GanzViel. Wenn wir jetzt
p0=n0/GanzViel p1=n1/GanzViel ... einführen können wird
dadraus:
p1 + p2*2 + p3 * 3 = avg
und
p0+p1+p2+p3=1
(p0 .. p3 sind Fließkommazahlen)
Die p's kann man als Wahrscheinlichkeit interpretieren, mit der eine Zahl auftritt/auftreten muss.
Ausserdem hast du 2 Gleichungen und 4 Unbekannte...
Es gibt also beliebig viele Lösungen für dein Problem :-)
(Jedenfalls in diesem Beispiel .. oli_rand(0,3,10); hat keine Lösung, oli_rand(0,1,1); genau eine - die ist allerdings nicht so schwer rauszukriegen...)
Übrigens: eine Gleichverteilung: p0=p1=p2=p3 geht natürlich nicht, denn damit steht der Mittelwert avg ja schon fest.
Du kannst dir jetzt überlegen, dass du jeweils unterhalb des Mittelwertes gleichverteile Häufigkeit hast und jeweils oberhalb des Mittelwertes.
Im Beispiel ist nur 0 unterhalb des Mittelwertes, damit hat man für Werte unterhalb des Mittelwertes die Wahrscheinlichkeit p0.
Oberhalb des Mittelwertes liegen 1,2,3 mit der Wahrscheinlichkeit p1+p2+p3. Gleichverteilung dafür führt p1=p2=p3 ein.
Damit:
p1 + p1*2 + p1 * 3 = avg
4 *p1= avg
p1=avg/4 mit avg=1/2 => p1=1/8
p0 + 3*p1=1
p0=1-3*p1 eingesetzt: p0=1-3/8=5/8
so, jetzt kann man auch deine Frage beantworten: die 0 muss (durchschnittlich!) 5 mal vorkommen wenn die 1, 2 und 3 jeweils einmal vorkommen.
Gruß,
Carsten
P.S.:
zum Testen
oli_rand(unten,oben,avg) // Parameter werden ignoriert und zu 0,3, ? fest angenommen)
{
if(z=rand(0,7)<3) // rand liefert hier zahlen von 0 bis 7 incl. gleichverteilt
return z+1;
else
return 0;
}
hi carsten,
vielen dank für deine antwort!
ich muss das jetzt erstmal in ruhe genauer studieren was du da alles geschrieben hast.
dank dir nochmals :)
gruss oliver