python⼆项分布产⽣随机数_从零构建统计随机变量⽣成器之
离散基础篇
本MyEncyclopedia定期发布AI,算法,⼯程类深度和前沿⽂章。学习本⽂的最佳姿势为点击⽂末在看,发送本⽂链接到桌⾯版浏览器,打开⽂末阅读原⽂,敲⼊代码运⾏。
在本系列中,我们会从第⼀性原理出发,从零开始构建统计学中的常见分布的随机变量⽣成器,包括⼆项分布,泊松分布,⾼斯分布等。在实现这些基础常见分布的过程中,会展⽰如何使⽤统计模拟的通⽤技术,包括 inverse CDF,Box-Muller,分布转换等。本期通过伯努利试验串联起来基础离散分布并通过代码来实现这些分布的⽣成函数,从零开始构建的原则是随机变量⽣成器实现只依赖 random() 产⽣ [0, 1.0] 之间的浮点数,不依赖于其他第三⽅API来完成。
均匀分布(离散)
离散均匀分布(Discrete Uniform Distribution)的随机变量是最为基本的,图中为 [0, 6] 七个整数的离散均匀分布。算法实现为,使⽤ [0, 1] 之间的随机数 u,再将 u 等⽐例扩展到指定的整数上下界。
实现代码
import random
from math import floor
def uniform(a: int, b: int) -> int:
assert a <= b
u = random.random()
return a + floor((b - a + 1) * u)
Github 代码地址:
持续模拟动画
伯努利分布
伯努利分布(Bernoulli Distribution)是support为0或者1的离散分布,0和1可以看成失败和成功两种可能。伯努利分布指定了成功的概率p,例如,下图是 p=0.4 的伯努利分布。
伯努利分布随机数实现也很直接,将随机值 u 根据 p 决定成功或者失败。
实现代码
import random
def bernoulli(p: float) -> int:
assert 0 <= p <= 1
u = random.random()
return 1 if u <= p else 0
Github 代码地址:
持续模拟动画
类别分布
类别分布(Categorical Distribution)是在伯努利分布的基础上扩展到了多个点,每个点同样由参数指定了其概率,因此,其参数从 p 扩展到了向量 ,如图所⽰为 时的类别分布。
实现代码
类别分布⽣成函数也扩展了伯努利分布的实现算法,将随机数 u 和累计概率向量作⽐较。在这个例⼦中, 转换成 ,再将 u 和 数组匹配,返回结果为第⼀个⼤于 u 的元素 index。实现上,我们可以以线性复杂度遍历数组,更好⼀点的⽅法是,⽤ python bisect函数通过⼆分法到index,将时间复杂度降到 。
import bisect
import random
from typing import List
def categorical(probs: List[float]) -> int:
assert abs(sum(probs) - 1.0)
cum = py()
for i in range(1, len(cum)):
cum[i] = cum[i-1] + probs[i]
u = random.random()
return bisect.bisect(cum, u)
持续模拟动画
⼆项分布
⼆项分布(Binomial Distribution)有两个参数 n 和 p,表⽰伯努利实验做n次后成功的次数。图中为 n=6,p=0.5的⼆项分布。
实现代码
⼆项分布⽣成算法可以通过伯努利试验的故事来实现,即调⽤ n 次伯努利分布⽣成函数,返回总的成功次数。
def binomial(n: int, p: float) -> int:
return sum(bernoulli(p) for _ in range(n))
Github 代码地址:
概率质量函数(PMF)
持续模拟动画
⼏何分布
⼏何分布(Geometric Distribution)和伯努利实验的关系是:⼏何分布是反复伯努利实验直⾄第⼀次成功时的失败次数。如图,当成功概率p=0.4时的⼏何分布。
实现代码
from discrete_bernoulli import bernoulli
def geometric(p: float) -> int:
fail_num = 0
while not bernoulli(p):
fail_num += 1
return fail_num
Github 代码地址:
概率质量函数(PMF)
持续模拟动画
负⼆项分布
负⼆项分布(Negative Binomial Distribution)是尝试伯努利试验直⾄成功 r 次的失败次数。
实现代码
from discrete_bernoulli import bernoulli
def negative_binomial(r: int, p: float) -> int:
failures = 0
while r:
success = bernoulli(p)
if success:
r -= 1
else:
failures += 1
return failures
Github 代码地址:
概率质量函数(PMF)
持续模拟动画
超⼏何分布
超⼏何分布(HyperGeometric Distribution)的意义是从总数为N的集合抽取n次后成功的次数。具体来说,集合由K个表⽰成功的元素和N-K个表⽰失败的元素组成,并且抽取时没有替换(without replacement)情况下的成功次数。注意,超⼏何分布和⼆项分布的区别仅在于有⽆替换。
实现代码
from discrete_bernoulli import bernoulli
def hypergeometric(N: int, K_succ_num: int, n_trial_num: int) -> int:
x = N - K_succ_num
n_hit = 0
while n_trial_num:
hit = bernoulli(K_succ_num / (K_succ_num + x))
n_hit += hit
if hit:
K_succ_num -= 1
else:
x -= 1
if K_succ_num == 0:
return n_hit
n_trial_num -= 1
return n_hit
Github 代码地址:
概率质量函数(PMF)
持续模拟动画
random python负超⼏何分布
负超⼏何分布(Negative Hypergeometric Distribution)的意义是从总数为N的集合中,⽆替换下抽取直⾄ r 次失败时,成功的次数。实现代码
from discrete_bernoulli import bernoulli
def negative_hypergeometric(N: int, K_success_num: int, r_fail_times: int) -> int:
fail_num = N - K_success_num
succ_trials = 0
while r_fail_times:
success = bernoulli(K_success_num / (K_success_num + fail_num))
if success:
K_success_num -= 1
succ_trials += 1
if K_success_num == 0: # no more success elements
return succ_trials
else:
fail_num -= 1
r_fail_times -= 1
return succ_trials
概率质量函数(PMF)
持续模拟动画
伯努利试验总结
下表总结了上⾯四种和伯努利试验有关的离散分布的具体区别。
有替换
⽆替换
固定尝试次数
⼆项 Binomial
超⼏何 Hypergeometric
固定成功次数
负⼆项 Negative Binomial
负超⼏何 Negative Hypergeometric

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。