読者です 読者をやめる 読者になる 読者になる

北海道苫小牧市出身の壮年PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

二項分布とポアソン分布

math scala

二項分布は試行回数が多くなると階乗周りの計算量が多くなる。一回の事象の発生確率pが十分に小さければ、ポアソン分布で近似ができる。

例えば、5枚の硬貨を投げてすべて表がでるかどうかを64回やったときの分布を二項分布とポアソン分布で比較すると、以下のように高い精度で近似できていることがわかる。

import scala.math.BigInt

def factor(n: BigInt): BigInt = if (n <= 1) 1 else n * factor(n - 1)

def combi(n: BigInt, m: BigInt): BigInt =
  factor(n) / factor(m) / factor(n - m)

def binomialDistribution(n: Int, p: Double): (Int) => Double = {
  import scala.math.pow
  def distribution(x: Int) = combi(n, x).toDouble * pow(p, x) * pow(1 - p, n - x)
  distribution _
}

def poissonDistribution(m: Double): (Int) => Double = {
  import scala.math.pow
  def distribution(x: Int) = pow(m, x).toDouble / pow(2.71828, m).toDouble / factor(x).toDouble
  distribution _
}

val n = 64
val p = 1.0 / 32.0
val binomial = binomialDistribution(n, p)
val poisson = poissonDistribution(n * p)

(0 to 10).foreach {n =>
  println("[n=%d]".format(n))
  println("binomial: %.3f".format(binomial(n)))
  println("poisson: %.3f".format(poisson(n)))
}
[n=0]
binomial: 0.131
poisson: 0.135
[n=1]
binomial: 0.271
poisson: 0.271
[n=2]
binomial: 0.275
poisson: 0.271
[n=3]
binomial: 0.183
poisson: 0.180
[n=4]
binomial: 0.090
poisson: 0.090
[n=5]
binomial: 0.035
poisson: 0.036
[n=6]
binomial: 0.011
poisson: 0.012
[n=7]
binomial: 0.003
poisson: 0.003
[n=8]
binomial: 0.001
poisson: 0.001
[n=9]
binomial: 0.000
poisson: 0.000
[n=10]
binomial: 0.000
poisson: 0.000