Random() mit Tendenz

  • Hallo liebe AutoIT'ler,

    ich bin auf der Suche nach einer Zufallsfunktion, die mir Zahlen zwischen 1 und 5 ausgibt.
    ABER: ich würde gerne eine Tendenz für einzelne Zahlen (z.B. 3) bzw. einen Zahlenraum (z.B. 1 - 3) angeben können.

    Das Ganze hat wahrscheinlich nicht wirklich was mit AutoIT zu tun (außer das ich es nutze :) ), sondern wohl eher mit Mathematik und Wahrscheinlichkeitsrechnung (oder? ?( ).

    Vielen Dank
    AAkira

    Einmal editiert, zuletzt von aakira (12. April 2012 um 07:50)

  • Dann stellt sich immer noch die Frage auf welche Art diese Tendenz angegeben wird.
    Was soll am Ende für eine Verteilungsart herauskommen und für die Umsetzung ganz wichtig: Gleitkommazahlen oder Integer-Zahlen als Ergebnis?

  • Auch kommt es darauf an, welche Flag du bei Random verwendest. Wenn du nur mit ganzen Zahlen arbeitest, ist es ja einfach.
    Bei

    [autoit]

    Random (1,3,1)

    [/autoit]


    ist die Warscheinlichkeit, eine bestimmte Zahl zu bekommen 1/3.
    Was du mit Tendenz meinst, habe ich auch nicht ganz verstanden, aber ich vermute mal, du willst ermitteln, welche Zahl in x Durchläufen am häufigsten auftritt, oder?
    Das würde ich dann so machen: Nimm einfach 3 Variablen, gib ihnen die Namen $eins, $zwei, $drei und setze alle auf 0. Wenn z.B. eine 2 "gewürfelt" wird, erhöhst du den Wert von $zwei um eins. Das machst du dann bei jedem Durchlauf und am Ende hast du deine Tendenz. Eleganter lässt sich das natürlich mit Arrays lösen, das wird dann aber ein bisschen komplizierter.

  • Ich hoffe ich hab dich richtig verstanden... Meinst du das in etwa so?

    Spoiler anzeigen
    [autoit]

    Dim $aTest[3][3] = [[2]] ;Anzahl der Bereiche
    $aTest[1][0] = 0.9 ;Wahrscheinlichkeit für ersten Bereich (Summe aller Wahrscheinlichkeiten muss 1 sein)
    $aTest[1][1] = 1 ;Erster Bereich Minimum
    $aTest[1][2] = 3 ;Erster Bereich Maximum
    $aTest[2][0] = 0.1 ;Wahrscheinlichkeit für zweiten Bereich
    $aTest[2][1] = 4 ;Zweiter Bereich Minimum
    $aTest[2][2] = 6 ;Zweiter Bereich Maximum

    [/autoit] [autoit][/autoit] [autoit]

    $iCount = 0
    For $i = 1 To 10000
    $iRandom = _RandomPropabilyty($aTest)
    If $iRandom <= 3 Then $iCount += 1
    Next
    ConsoleWrite("Percentage of results between 1 & 3: " & $iCount / 100 & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Func _RandomPropabilyty($aProp)
    ;- Author: name22 (http://www.autoit.de)
    If Not IsArray($aProp) Then Return SetError(1, "", "")

    [/autoit] [autoit][/autoit] [autoit]

    Local $nRand = Random()
    Local $nProp = 0
    For $i = 1 To $aProp[0][0]
    $nProp += $aProp[$i][0]
    If $nRand <= $nProp Then Return Random($aProp[$i][1], $aProp[$i][2], 1)
    Next
    Return SetError(2, "", "")
    EndFunc ;==>_RandomPropabilyty

    [/autoit]


    Es ist noch nicht wirklich ausreichend getestet und optimiert, aber es scheint zu funktionieren.

  • Also (so beginnt man keinen Satz^^) ich habe mal eben geschaut und bin auf eine sehr schöne einfache Lösung gestoßen (im Kopf ! kein Google :D).

    Wenn man mehrere Random Funktionen verschachtelt ergibt sich als Logische Konsequenz immer eine Tendenz, trotz unveränderter "Streuweite".

    Auf der Grundlage habe ich eben 3 Funktionen gebastelt die jeweils unterschiedliche Tendenzen haben.
    1. Tendenz num Minimalwert.
    2. Tendenz zum Maximalwert.
    3. Tendenz zur Mitte.

    Auswertung
    Skript
    [autoit]


    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Local $Mittelwert
    Local $Anzahl = 99999
    Local $Min = 5
    Local $Max = 10
    Local $Ergebnisse[$Max-$Min+1]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $Anzahl Step 1
    $Ergebnisse[_Random($Min, $Max)-$Min] += 1
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Versuche: ' & $Anzahl & @CRLF & 'Minimalwert: ' & $Min & @CRLF & 'Maximalwert: ' & $Max & @CRLF & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To UBound($Ergebnisse) - 1 Step 1
    ConsoleWrite(StringRight('000' & $i + $Min, Ceiling(Log($Max)/Log(10)+1)) & ': (' & $Ergebnisse[$i] & ') ' & Round(100*($Ergebnisse[$i]/$Anzahl),2) & ' %' & @CRLF)
    $Mittelwert += $Ergebnisse[$i]*($i+$Min)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(@CRLF & 'Mittelwert: ' & Round($Mittelwert/$Anzahl,2) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Func _Random($Min, $Max) ; Tendenz zum kleinst möglichen Wert
    ;~ Return Int(Random($Min, Random($Min, $Max)+1))
    ;~ EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Func _Random($Min, $Max) ; Tendenz zum größt möglichen Wert
    ;~ Return Int(Random(Random($Min, $Max), $Max+1))
    ;~ EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Random($Min, $Max) ; Tendenz zur Mitte ( vermutlich normalverteilt. aber keine Gewähr dafür )
    Return Int(Random($Min+Random(0, ($Max-$Min)/2), 1+$Max-Random(0, ($Max-$Min)/2)))
    EndFunc

    [/autoit]

    Edit: Das Beispiel ist für Integer Zahlen.
    Um auf Fließkommazahlen umzustellen muss nur das +1 bei jedem Maximalwert und das Int(blabla) entfernt werden.

    lg
    M

  • Na, dann versuche ich das einmal zu erklären:

    wenn ich die normale Random-Funktion [hier: random (1,5,1)] benutze, bekomme ich Zufallszahlen zwischen 1 und 5 (z.B. bei 30 Durchgängen). Ich möchte jetzt aber die "Zufallsmäßigkeit" etwas steuern und den "Schwerpunkt" der Zufallszahlen auf z.B. 1 bis 3 legen. D.h. es sollen die Zahlen 1, 2 oder 3 öfter, als die Zahlen 4 und 5 vorkommen. Also soll die Wahrscheinlichkeit, dass die Zahlen zwischen 1-3 vorkommen, erhöht werden. Alle Zahlen sind übrigens Integer!

    Das Programm von name22 ist toll - auch wenn ich es nicht verstehe :)

  • Das ist noch bisschen schwammig.
    Sollen die Zahlen 1-3 jetzt alle gleichhäufig (aber immer noch öfter vorkommen als 4-5) oder soll hin zur 1 die Häufigkeit tendenziell zunehmen.
    Daher ergibt sich auch die Frage wie du das konkret umgesetzt haben willst.
    Also du musst ja irgendwie angeben auf welche Art und Weise und wie oft eine Zahl öfter vorkommt als eine andere Zahl.
    Wie gibst du das an?

    Wenn es nur ganzzahlige Häufigkeitsfaktoren sind und nur Ganzzahlen ausgegeben werden sollen kannst du die Häufigkeit relativ einfach durch Wiederholung dieser Zahl in der Zahlenmenge beeinflussen:

    [autoit]

    Global $a_Zahlen[8] = [1, 1, 2, 2, 3, 3, 4, 5]
    MsgBox(0, "", "Zufallszahl: " & $a_Zahlen[Random(0, UBound($a_Zahlen) - 1, 1)])

    [/autoit]
  • Die Wahrscheinlichkeit zwischen den Zahlen (hier: 1 bis 3) sollte gleich sein. Die Angabe der Wahrscheinlichkeit könnte ich mir durch eine Prozenteingabe vorstellen. Also z.B. 10% sollen die Zahlen 1-3 öfter vorkommen.

    Das ist noch bisschen schwammig.
    Sollen die Zahlen 1-3 jetzt alle gleichhäufig (aber immer noch öfter vorkommen als 4-5) oder soll hin zur 1 die Häufigkeit tendenziell zunehmen.
    Daher ergibt sich auch die Frage wie du das konkret umgesetzt haben willst.
    Also du musst ja irgendwie angeben auf welche Art und Weise und wie oft eine Zahl öfter vorkommt als eine andere Zahl.
    Wie gibst du das an?

    Wenn es nur ganzzahlige Häufigkeitsfaktoren sind und nur Ganzzahlen ausgegeben werden sollen kannst du die Häufigkeit relativ einfach durch Wiederholung dieser Zahl in der Zahlenmenge beeinflussen:

    [autoit]

    Global $a_Zahlen[8] = [1, 1, 2, 2, 3, 3, 4, 5]
    MsgBox(0, "", "Zufallszahl: " & $a_Zahlen[Random(0, UBound($a_Zahlen) - 1, 1)])

    [/autoit]
  • Die Wahrscheinlichkeit zwischen den Zahlen (hier: 1 bis 3) sollte gleich sein. Die Angabe der Wahrscheinlichkeit könnte ich mir durch eine Prozenteingabe vorstellen. Also z.B. 10% sollen die Zahlen 1-3 öfter vorkommen.


    Alle 3 Zahlen zusammen 10% häufiger oder jede einzelne?

    Wie willst du diese Angabe konkret im Programm umsetzen?
    Möchtest du direkt die Wahrscheinlichkeit für jede einzelne Zahl angeben?

  • Hier meine Version:

    [autoit]


    #include <Array.au3>
    Global $aZahlen[5][3] = [[1, 10, 0], [2, 10, 0], [3, 30, 0], [4, 40, 0], [5, 10, 0]] ; -> Array besteht aus Zahl, Wahrscheinlichkeit [0-100], Häufigkeit
    ; in diesem Beispiel soll die 4 am häufigsten vorkommen, dann die 3 und zu letzt der Rest.

    [/autoit][autoit][/autoit][autoit]

    Random_Tendenz($aZahlen)

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($aZahlen, "Wahrscheinlichkeit mit Tendenz", -1, 0, "", "|", "|Zahl|Wahrscheinlichkeit (%)|Häufigkeit")

    [/autoit][autoit][/autoit][autoit]

    Func Random_Tendenz(ByRef $aZahlen, $loops = 10000)
    Local $i, $j, $k = 1
    Local $aRange[101]
    For $i = 0 To UBound($aZahlen) - 1
    For $j = 1 To $aZahlen[$i][1]
    $aRange[$k] = $i
    $k += 1
    Next
    Next
    For $i = 1 To $loops
    $aZahlen[$aRange[Random(1, 100, 1)]][2] += 1
    Next
    $aRange = 0
    EndFunc

    [/autoit]


    Passt das soweit?

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Kommt wie gesagt darauf an was aakira nun genau haben möchte und braucht.
    Wenn ihm derartige ganzzahlige Faktoren reichen sollte es so gehen.
    Wenn er jedoch speziell sagt dass z.B. die 4 9.74x wahrscheinlicher vorkommen soll wie die 5 stößt man dann damit schnell an Umsetzungsschwierigkeiten.

    Hier daher mein Vorschlag für sein Beispiel das die 1-3 jeweils 10% öfter vorkommen sollen als die 4-5:

    Spoiler anzeigen
    [autoit]

    ; Zahlen und ihre relative Wahrscheinlichkeit als 2D-Array:
    Global $a_Zahlen[5][2] = [ _
    [1, 1.1], _
    [2, 1.1], _
    [3, 1.1], _
    [4, 1.0], _
    [5, 1.0]]

    [/autoit] [autoit][/autoit] [autoit]

    ;Summe der Wahrscheinlichkeiten bilden (zur Normalisierung)
    Global $dSum = 0
    For $i = 0 To UBound($a_Zahlen) - 1
    $dSum += $a_Zahlen[$i][1]
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;Auf den Zahlenraum [0,1] abbilden:
    Global $a_Grenzen[UBound($a_Zahlen)] ; neue Grenzen innerhalb von [0,1] für die einzelnen Zahlen
    Global $dX = 0
    For $i = 0 To UBound($a_Zahlen) - 1
    $dX += $a_Zahlen[$i][1]
    $a_Grenzen[$i] = $dX / $dSum
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ;Zufallszahlen mit den vorgegebenen relativen Wahrscheinlichkeiten erzeugen:
    For $i = 0 To 100
    ConsoleWrite(MyRandomNumber($a_Zahlen, $a_Grenzen) & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Funktion welche mit den Ausgangszahlen und den bestimmten Grenzen eine Zufallszahl erzeugt
    Func MyRandomNumber(ByRef $a_Zahlen, ByRef $a_Grenzen)
    Local $d_Zahl = Random()
    For $i = 0 To UBound($a_Grenzen) - 1
    If $d_Zahl <= $a_Grenzen[$i] Then
    Return $a_Zahlen[$i][0]
    EndIf
    Next
    EndFunc

    [/autoit]
  • Guten Morgen liebe AutoIT'ler,

    uiii, hier gibt es ja wirklich eine äußerst aktive Comnunity :)
    Der Vorschlag von AsprinJunkie stimmt ziemlich genau mit meinem Ansinnen überein. Damit kann ich gut was anfangen.

    Vielen Dank für Eure Mühe und lG
    AAkira

  • Nur mal für mich selbst gefragt:
    Würde das hier nicht das selbe machen, oder habe ich da einen logischen Denkfehler?

    [autoit]

    Local $iZahl

    [/autoit][autoit][/autoit][autoit]

    Switch Random(1, 110, 1)
    Case 1 To 100
    $iZahl = Random(1,5,1)
    Case 101 To 110
    $iZahl = Random(1,3,1)
    EndSwitch

    [/autoit][autoit][/autoit][autoit]

    MsgBox(0,'',$iZahl)

    [/autoit]
  • Das sollte auch funzen, nur musst du viele Switch Case Anweisungen hard coden, wenn du n Zahlen hast mit m Tendenzen haben willst.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯