2016-02-15 2 views
6

I einen Generator in Scalacheck erstellen möchten, die zufällig in Richtung Nummern näher zu 1.Scalacheck: eine ganze Zahl mit benutzerdefinierten Wahrscheinlichkeitsverteilung wählen

Gen.choose() verteilt Zahlen Zahlen zwischen etwa 1 und 100, jedoch mit einer glockenartigen Vorspannung erzeugt zwischen der MIN- und der MAX-Wert:

scala> (1 to 10).flatMap(_ => Gen.choose(1,100).sample).toList.sorted 
res14: List[Int] = List(7, 21, 30, 46, 52, 64, 66, 68, 86, 86) 

und Gen.chooseNum() hat einen zusätzlichen Bias für die oberen und unteren Grenzen:

scala> (1 to 10).flatMap(_ => Gen.chooseNum(1,100).sample).toList.sorted 
res15: List[Int] = List(1, 1, 1, 61, 85, 86, 91, 92, 100, 100) 

Ich möchte eine choose() Funktion, die mir ein Ergebnis geben würde, die etwa wie folgt aussieht:

scala> (1 to 10).flatMap(_ => choose(1,100).sample).toList.sorted 
res15: List[Int] = List(1, 1, 1, 2, 5, 11, 18, 35, 49, 100) 

Ich sehe, dass choose() und chooseNum() nehmen eine implizite Choose Eigenschaft als Argument. Soll ich das benutzen?

+0

Wenn durch Bell-wie Sie Gauß bedeuten, dann ist es unmöglich, weil die Gaußsche (normale) Verteilung symmetrisch ist um den Mittelwert (die Sie 1 sein wollen), so dass Sie viele negative Werte (Sie kann den absoluten Wert bekommen und dann ist es wahrscheinlich das, was du willst), trotzdem gibt es zwei Möglichkeiten, um th zu erreichen Die erste Möglichkeit besteht darin, die Gleichverteilung (die standardmäßig von 'Gen.choose' verwendet wird) in die Normalverteilung zu konvertieren. Die zweite Möglichkeit besteht darin, Zufallsgeneratoren zu verwenden, die die Gaußverteilung unterstützen. Die Antwort sollte jedoch @LaloInDublin enthalten Ihre Anforderung) –

+2

Keine Antwort, aber es lohnt sich zu überlegen, warum Sie das wirklich wollen oder müssen. Die Verzerrung in "chooseNum" usw. ist darauf ausgelegt, Fälle von Ecken zu erfassen. Es ist weniger klar, warum Sie die Art der Verteilung, die Sie beschreiben, möchten. –

Antwort

4

könnten Sie verwenden Gen.frequency()(1):

val frequencies = List(
    (50000, Gen.choose(0, 9)), 
    (38209, Gen.choose(10, 19)), 
    (27425, Gen.choose(20, 29)), 
    (18406, Gen.choose(30, 39)), 
    (11507, Gen.choose(40, 49)), 
    (6681, Gen.choose(50, 59)), 
    (3593, Gen.choose(60, 69)), 
    (1786, Gen.choose(70, 79)), 
    ( 820, Gen.choose(80, 89)), 
    ( 347, Gen.choose(90, 100)) 
) 

(1 to 10).flatMap(_ => Gen.frequency(frequencies:_*).sample).toList 
res209: List[Int] = List(27, 21, 31, 1, 21, 18, 9, 29, 69, 29) 

ich die Frequenzen von https://en.wikipedia.org/wiki/Standard_normal_table#Complementary_cumulative bekam. Der Code ist nur ein Beispiel der Tabelle (% 3 oder Mod 3), aber ich denke, Sie können die Idee bekommen.

+0

Dies ist eine gute Annäherung :) –

+0

Danke. Ich habe am Ende eine einfachere Version verwendet, die mir eine ausreichende Annäherung für meine Testanforderungen gibt. – jjst

3

Ich kann nicht viel Kredit dafür nehmen, und werden Sie auf diese hervorragende Seite zeigen: http://www.javamex.com/tutorials/random_numbers/gaussian_distribution_2.shtml

Eine Menge davon abhängt, was man von „glockig“ bedeuten. Ihr Beispiel zeigt keine negativen Zahlen, aber die Zahl "1" kann nicht in der Mitte der Glocke sein und keine negativen Zahlen erzeugen, es sei denn, es handelt sich um eine sehr, sehr kleine Glocke!

Verzeihen Sie die wandelbar Schleife, aber ich benutze sie manchmal, wenn ich Werte in einer Sammlung bauen ablehnen müssen:

object Test_Stack extends App { 

    val r = new java.util.Random() 

    val maxBellAttempt = 102 
    val stdv = maxBellAttempt/3 //this number * 3 will happen about 99% of the time 


    val collectSize = 100000 
    var filled = false 


    val l = scala.collection.mutable.Buffer[Int]() 

    //ref article above "What are the minimum and maximum values with nextGaussian()?" 

    while(l.size < collectSize){ 

    val temp = (r.nextGaussian() * stdv + 1).abs.round.toInt //the +1 is the mean(avg) offset. can be whatever 
    //the abs is clipping the curve in half you could remove it but you'd need to move the +1 over more 

    if (temp <= maxBellAttempt) l+= temp 

    } 

    val res = l.to[scala.collection.immutable.Seq] 
    //println(res.mkString("\n")) 
} 

Hier ist die Verteilung ich die Ausgabe in Excel nur geklebt und hat eine „countIf“ die zeigen, Häufigkeit von jedem:

Verwandte Themen