2012-07-12 54 views
3

有限長度N的浮點數(0和1之間)的給定序列表示整數0..N-1上的分佈函數。我們試圖從這個分佈中抽取一個隨機數。一種方法是在[0,1](float)中繪製一個統一的隨機變量,然後計算該數字的逆累積分佈函數。從存儲爲F#中概率序列的離散分佈函數中繪製一個隨機數

如果分佈在陣列中,所述代碼看起來是這樣的:

let matched distribution draw = 
    let rec matchRest distribution draw start = 
    if start = Array.length distribution then start-1 
    else 
     let left = draw - distribution.[start] 
     if left <= 0 then start 
     else matchRest distribution left (start+1) 
    matchRest distribution draw 0 

其中distribution是分佈函數和draw是均勻的[0,1]號碼。

如何在分配任何序列時重寫此函數以工作?很明顯,我可以創建一個臨時陣列,但它似乎不是一個優雅的解決方案...

回答

5

您的matched函數是一個搜索過程。您不必分解序列來搜索適當的索引;從Seq module高階功能,可以幫助您:

/// Taken from http://missingfaktor.blogspot.in/2012/02/f-option-cheat-sheet.html 
let getOrElse d = function 
    | Some a -> a 
    | None -> d 

let matched distribution draw = 
    distribution 
    |> Seq.scan (fun (s, d0) d -> (s+1, d0-d)) (0, draw) 
    |> Seq.tryPick (fun (s, d) -> if d <= 0 then Some s else None) 
    |> getOrElse (Seq.length distribution-1) 

在最壞的情況下,你仍然可以通過Seq.length枚舉整個序列。如果可能的話,我認爲最好將Seq.length distribution-1更改爲已知常數。

+0

我在想這種方法,但我不認爲你現在的版本是正確的 - 因爲你對所有的索引使用相同的「draw」數量,而它應該會下降。 – Grzenio 2012-07-12 13:10:37

+0

謝謝,我修好了:)。 – pad 2012-07-12 13:14:57