2016-02-15 13 views
6

Tôi muốn tạo ra một máy phát điện trong ScalaCheck mà tạo ra số giữa nói 1 đến 100, nhưng với một sự thiên vị chuông giống như đối với số gần gũi hơn với 1.ScalaCheck: chọn một số nguyên với phân bố xác suất tùy chỉnh

Gen.choose() phân phối số một cách ngẫu nhiên giữa giá trị min và max:

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) 

Gen.chooseNum() có xu hướng gia tăng đối với các giới hạn trên và dưới:

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) 

Tôi muốn một chức năng choose() rằng sẽ cung cấp cho tôi một kết quả mà trông giống như sau:

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) 

Tôi thấy rằng choose()chooseNum() có một tiềm ẩn Choose đặc điểm như một cuộc tranh cãi. Tôi có nên sử dụng nó không?

+0

Nếu theo Bell giống như bạn ngụ ý Gaussian thì không thể vì phân phối Gaussian (bình thường) là đối xứng xung quanh giá trị trung bình (bạn muốn 1) để bạn nhận được nhiều giá trị âm có thể nhận được giá trị tuyệt đối và sau đó nó có thể là những gì bạn muốn), dù sao có hai cách để đạt được thứ là, cách thứ nhất là chuyển đổi phân bố đồng nhất (được sử dụng bởi 'Gen.choose' theo mặc định) thành phân phối chuẩn, cách thứ hai là sử dụng các trình tạo ngẫu nhiên hỗ trợ phân phối Gaussian, dù sao câu trả lời được đưa ra bởi @LaloInDublin yêu cầu của bạn) –

+2

Không phải là câu trả lời nhưng đáng xem xét tại sao bạn thực sự muốn hoặc cần phải làm điều này. Sự thiên vị trong 'selectNum', v.v. được thiết kế để nắm bắt các trường hợp góc - ít rõ ràng lý do tại sao bạn muốn loại phân phối mà bạn mô tả. –

Trả lời

4

Bạn có thể sử dụng 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) 

Tôi có tần số từ https://en.wikipedia.org/wiki/Standard_normal_table#Complementary_cumulative. Mã chỉ là một mẫu của bảng (% 3 hoặc mod 3), nhưng tôi nghĩ bạn có thể có được ý tưởng.

+0

Đây là một xấp xỉ tốt :) –

+0

Cảm ơn. Tôi đã kết thúc bằng cách sử dụng một phiên bản đơn giản của điều này, mang lại cho tôi một xấp xỉ đủ cho các nhu cầu thử nghiệm của tôi. – jjst

3

Tôi không thể lấy tín dụng nhiều cho việc này, và sẽ chỉ cho bạn trang tuyệt vời này: http://www.javamex.com/tutorials/random_numbers/gaussian_distribution_2.shtml

Rất nhiều điều này phụ thuộc những gì bạn có ý nghĩa bởi "chuông giống như". Ví dụ của bạn không hiển thị bất kỳ số âm nào nhưng số "1" không thể ở giữa chuông và không tạo ra bất kỳ số âm nào trừ khi đó là một tiếng chuông rất nhỏ!

Hãy tha thứ cho vòng lặp có thể thay đổi nhưng tôi sử dụng chúng đôi khi tôi phải từ chối giá trị trong một bộ sưu tập xây dựng:

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")) 
} 

Đây là sự phân bố tôi chỉ dán đầu ra vào excel và đã một "COUNTIF" để hiển thị freq của mỗi: enter image description here

Các vấn đề liên quan