F# で最高事後密度区間を求める


F# で最高事後密度区間 (highest posterior density interval, HPDI) を求めます。

let hpdi mass (values : float list) =
   let size = List.length values
   let shift = int <| mass * float size
   let sorted = List.sort values
   let width = Seq.map2 (-) (Seq.skip shift sorted) sorted |> Seq.toList
   let minIndex =
      Seq.zip (Seq.initInfinite id) width
      |> Seq.minBy snd
      |> fst
   sorted.[minIndex], sorted.[minIndex + shift]

取りうる区間の中でもっとも幅が狭いものを選択しています。

例として標準正規乱数を 100,000 個生成してその 95% HPDI を求めてみます。

let rec normal (random : System.Random) =
   seq {
      let u1 = random.NextDouble ()
      let u2 = random.NextDouble ()
      let r = sqrt <| -2.0 * log u1
      let theta = 2.0 * System.Math.PI * u2
      yield r * sin theta
      yield r * cos theta
      yield! normal random
   }
let samples = normal (System.Random ()) |> Seq.take 100000 |> Seq.toList
hpdi 0.95 samples |> printfn "%A"  // (-1.940508623, 1.96964806)

結果がおよそ (-1.96, 1.96) になっていますね。