Python 概率生成问题案例详解

 更新时间:2021年9月10日 12:01  点击:1466

概率生成问题

有一枚不均匀的硬币,要求产生均匀的概率分布
有一枚均匀的硬币,要求产生不均匀的概率分布,如 0.25 和 0.75
利用 Rand7() 实现 Rand10()

不均匀硬币 产生等概率

现有一枚不均匀的硬币 coin(),能够返回 0、1 两个值,其概率分别为 0.6、0.4。要求使用这枚硬币,产生均匀的概率分布。即编写一个函数 coin_new() 使得它返回 0、1 的概率均为 0.5。

# 不均匀硬币,返回 0、1 的概率分别为 0.6、0.4
def coin():
    return 0 if random.randint(1,10) > 4 else 1

统计抛两次硬币的结果的概率分布:

结果 0 1
0 0.60.6=0.36 0.60.4=0.24
1 0.40.6=0.24 0.40.4=0.16

连续抛两枚硬币得到 0 1 和 1 0 的概率分布是相同的。因此这道题的解法就是连续抛两次硬币,如果得到 0 1,返回 0;如果得到 1 0,返回 1;如果两次结果相同,则重新抛。

以此类推,无论这枚不均匀硬币的概率是多少,都可以用这种方法得到等概率的结果。

ddef coin_new():
    while True:
        a = coin()
        if coin() != a:  
            return a

完整测试代码:

def coin():
    return 0 if random.randint(1,10) > 4 else 1

def coin_new():
    while True:
        a = coin()
        if coin() != a:  
            return a
if __name__ == '__main__':
    a = 0
    b = 0
    n = 100000
    for _ in range(n):
        if coin_new():a += 1
        if coin():b += 1

    print(f"1:{a/n},1:{b/n}")

均匀硬币 产生不等概率

现有一枚均匀的硬币 coin(),能够返回 0、1 两个值,其概率均为 0.5。要求编写一个函数 coin_new(),使得它返回指定的 0、1 概率分布。

# 均匀硬币 
def coin():
    return random.randint(0,1)  

P(0) = 1/4,P(1) = 3/4

对于均匀硬币而言,连续抛两次,得到 0 0、0 1、1 0、1 1 的概率均为 1/4。显然,只需要连续抛两次硬币,如果得到 0 0,返回 0,其他情况返回 1。

def coin_new():
    return coin() or coin()

P(0) = 1/3,P(1) = 2/3

连续抛两次硬币。如果得到 1 1,返回 0;如果得到 1 0 或 0 1,返回 1;如果得到 0 0,继续抛硬币。

def coin_new():
    while True:
        a, b = coin(), coin()
        if a & b: return 0
        if a | b: return 1

P(0) = 0.3,P(1) = 0.7

每抛一次硬币,会得到二进制数的一位,连续抛 4 次硬币,可以等概率生成 [0, 15] 的每个数,记为 x。去掉 [10, 15],剩下 [0, 9] 的每个数依然是等概率的。如果 x ∈ [ 0 , 2 ] x \in [0, 2] x∈[0,2],返回 0; x ∈ [ 4 , 9 ] x \in [4, 9] x∈[4,9],返回 1; x ≥ 10 x ≥ 10 x≥10,重复上述过程。

def coin_new():
    while True:
        x = 0
        for _ in range(4):
            x = (x << 1) + coin()
        if x <= 2: return 0
        if x <= 9: return 1

总结

每抛一次硬币,会得到二进制数的一位,连续抛 k 次硬币,可以等概率生成 [ 0 , 2 k − 1 ] [0, 2^k-1] [0,2k−1] 的每个数在 [ 0 , 2 k − 1 ] [0, 2^k-1] [0,2k−1][ 中,选取 m 个数返回 0,n 个数返回 1,则 0、1 的概率分别为 m m + n \frac{m}{m+n} m+nm​ 、 n m + n \frac{n}{m+n} m+nn​。

关于 k 的选择,最少需要满足 N < = 2 k − 1 N <= 2^k-1 N<=2k−1,N 是生成对应概率分布至少需要多少个不同数字。比如要生成 1/3、2/3 的分布,至少需要 3 个不同数字,则 N = 3, k = 2;要生成 3/10、7/10 的分布,至少需要 10 个数字,则 N = 10, k = 4。

k 最多则没有限制,我们总可以通过抛更多次硬币来解决问题,只需要把无用的数字舍弃即可。但我们的目的是尽可能减少无用数字的比例,因为每次遇到无用数字时,都需要重新生成新的数字。

Rand7 生成 Rand10

已有方法 Rand7() 可生成 1 到 7 范围内的均匀随机整数,试写一个方法 Rand10() 生成 1 到 10 范围内的均匀随机整数。

抛硬币可以看作是 Rand2(),均匀生成 0、1 两个整数。如何根据 Rand2() 生成 Rand10()?将每次抛硬币的结果,看作二进制的每一位,就可以得到 [ 0 , 2 k − 1 ] [0, 2^k-1] [0,2k−1] 范围内的均匀随机整数。只需要抛 4 次硬币,就能得到 [0, 15] 范围的整数。返回 [1, 10] 范围的整数,其他情况则重新抛硬币。

def rand10():
    while True:
        x = 0
        for _ in range(4):
            x = x << 1 + rand2()
            
        if 1 <= x <= 10: return x

取 Rand7() - 1 作为对应的 7 进制位。每执行 k 次 Rand7(),将得到一个 k 位的 7 进制整数,在 [ 0 , 7 k − 1 ] [0, 7^k-1] [0,7k−1] 范围内均匀分布。

只需执行 k = 2 次 Rand7(),就可以得到范围为 [0, 48] 的均匀整数:

当 x ∈ [ 1 , 10 ] x \in [1, 10] x∈[1,10] 时返回 x,否则重新计算:

def rand10():
    while True:
        x = (rand7() - 1) * 7 + (rand7() - 1);
        if 1 <= x <= 10: return x

进一步优化

选择 [1, 40] 范围里的数,通过取余运算来得到 [1, 10] 范围的数:

def rand10():
    while True:
        x = (rand7() - 1) * 7 + (rand7() - 1)
        if 1 <= x <= 40:
            return x % 10 + 1

对于上面这 9 个无用数字,计算 x % 40 可以得到 [0, 8] 范围的均匀随机整数。此时再调用一次 Rand7(),计算 (x % 40) * 7 + Rand7(),这相当于 Rand9() * 7 + Rand7()。显然,可以得到 [1, 63] 范围的均匀随机整数。这时 [1, 60] 范围里的数都可以用来作取余运算,只有 61、62、63 共 3 个无用数字:

def rand10():
    while True:
        x = (rand7() - 1) * 7 + (rand7() - 1)
        if 1 <= x <= 40:
            return x % 10 + 1   
            
    	x = (x % 40) * 7 + rand7() # 1~63
    	if x <= 60: return x % 10 + 1

对于 61、62、63,再调用一次 Rand7(),计算 (x - 61) * 7 + Rand7(),相当于 Rand3() * 7 + Rand7(),可以得到 [1, 21] 范围的均匀随机整数,这时再作取余运算,只有 1 个无用数字(21):

def rand10():
    while True:
        x = (rand7() - 1) * 7 + (rand7() - 1)
        if 1 <= x <= 40:
            return x % 10 + 1   
            
    	x = (x % 40) * 7 + rand7() # 1~63
    	if x <= 60: return x % 10 + 1

        x = (x - 61) * 7 + 7 # 1~21
        if x <= 20: return x % 10 + 1

每次 while 执行的时候,只有 1 个无用数字(21)会被舍弃,重新执行的概率很低。

RandM 生成 RandN

已知 RandM() 可以等概率的生成 [0, M-1] 范围的随机整数,那么执行 k 次,每次都得到 M 进制的一位,可以等概率生成 [ 0 , M k − 1 ] [0, M^k-1] [0,Mk−1] 范围的随机整数,记为 x。

RandN 至少需要 N 个均匀随机整数,因此只需要取 k,使得 M k − 1 > = N M^k-1 >= N Mk−1>=N 即可,此时有多种方式得到 RandN:
一种是只在 x ∈ [ 0 , N − 1 ] x \in [0, N-1] x∈[0,N−1] 时返回 x,另一种是利用取余运算,在保证等概率的前提下,尽可能多的利用生成的数字,从而减少舍弃的数字比例,降低 while 重复执行的概率。

到此这篇关于Python 概率生成问题案例详解的文章就介绍到这了,更多相关Python 概率生成问题内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • python opencv 画外接矩形框的完整代码

    这篇文章主要介绍了python-opencv-画外接矩形框的实例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-04
  • Python astype(np.float)函数使用方法解析

    这篇文章主要介绍了Python astype(np.float)函数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-08
  • 最炫Python烟花代码全解析

    2022虎年新年即将来临,小编为大家带来了一个利用Python编写的虎年烟花特效,堪称全网最绚烂,文中的示例代码简洁易懂,感兴趣的同学可以动手试一试...2022-02-14
  • python中numpy.empty()函数实例讲解

    在本篇文章里小编给大家分享的是一篇关于python中numpy.empty()函数实例讲解内容,对此有兴趣的朋友们可以学习下。...2021-02-06
  • python-for x in range的用法(注意要点、细节)

    这篇文章主要介绍了python-for x in range的用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-10
  • Python 图片转数组,二进制互转操作

    这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
  • Python中的imread()函数用法说明

    这篇文章主要介绍了Python中的imread()函数用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-16
  • python实现b站直播自动发送弹幕功能

    这篇文章主要介绍了python如何实现b站直播自动发送弹幕,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下...2021-02-20
  • python Matplotlib基础--如何添加文本和标注

    这篇文章主要介绍了python Matplotlib基础--如何添加文本和标注,帮助大家更好的利用Matplotlib绘制图表,感兴趣的朋友可以了解下...2021-01-26
  • 解决python 使用openpyxl读写大文件的坑

    这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
  • python 计算方位角实例(根据两点的坐标计算)

    今天小编就为大家分享一篇python 计算方位角实例(根据两点的坐标计算),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
  • python实现双色球随机选号

    这篇文章主要为大家详细介绍了python实现双色球随机选号,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-02
  • python中使用np.delete()的实例方法

    在本篇文章里小编给大家整理的是一篇关于python中使用np.delete()的实例方法,对此有兴趣的朋友们可以学习参考下。...2021-02-01
  • 使用Python的pencolor函数实现渐变色功能

    这篇文章主要介绍了使用Python的pencolor函数实现渐变色功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-09
  • python自动化办公操作PPT的实现

    这篇文章主要介绍了python自动化办公操作PPT的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-05
  • Python getsizeof()和getsize()区分详解

    这篇文章主要介绍了Python getsizeof()和getsize()区分详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-20
  • 解决python 两个时间戳相减出现结果错误的问题

    这篇文章主要介绍了解决python 两个时间戳相减出现结果错误的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-12
  • python实现学生通讯录管理系统

    这篇文章主要为大家详细介绍了python实现学生通讯录管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-25
  • PyTorch一小时掌握之迁移学习篇

    这篇文章主要介绍了PyTorch一小时掌握之迁移学习篇,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-08
  • Python绘制的爱心树与表白代码(完整代码)

    这篇文章主要介绍了Python绘制的爱心树与表白代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-06