我是靠谱客的博主 明理秀发,最近开发中收集的这篇文章主要介绍根据权重生成随机数,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

想设计一个算法在一个集合中随便选一个数,但是选出来这个数的概率要和这个数的大小成正比。也就是说希望越大的数被大概率的选出来。

这个问题更清晰点儿描述是,有一组数字,他们都带有不同的权重,现在要从中“随机”抽一个数字,但是抽到某个数字的概率要正比于他的权重。假设这个集合中的元素和其对应权重为{‘A’:50,‘B’:10,‘C’:100,‘D’:3,‘E’:60,‘F’:25}。

方法一

如果随机选的话,在一个list中出现的次数多被选中的概率就会大。所以可以按照权重组合一个list,在这个list中A有50个,B有10个,C有100个,等等。有了list之后,从中随机选一个。这样选取的时间负责度是O(1)。但是如果数字很多,权重又很大的话,那么空间负责度会很高。

import random

data = {'A': 50, 'B': 10, 'C': 100, 'D': 3, 'E': 60, 'F': 25}
value_list = []
for key, value in data.items():
    value_list += value*[key]
pick_value = random.choice(value_list)

进行100万次实验,计数每个字母被选中的次数。结果如下图所示

可以看出多次实验的结果,每个字符选中的次数确实与权重成正比。

方法二(常用:之所以权重大被随机的概率大,是因为sum实际上也是区间的一种表现形式)

对每个元素的权重进行加和记为sum,在1到sum之间随机选一个数。之后遍历整个集合,统计遍历到的项的权重之和,如果大于sum,则选择这个数。该方法需要遍历集合,时间复杂度为O(n)

复制代码

import random
data = {'A': 50, 'B': 10, 'C': 100, 'D': 3, 'E': 60, 'F': 25}
value_sum = sum(data.values())
for i in range(1000000):
t = random.randint(0, value_sum - 1)
for key, value in data.items():
t -= value
if t < 0:
pick_value = key
break

复制代码

多次实验统计被选中的元素的次数如下图

方法三

上面方法最坏的情况是遍历完所有的元素,但是如果权重大的元素能够先被遍历的话可以减少遍历次数。基于此,可以先对元素按照权重排序。但是这样排序的话也会比较花时间。可以计算一个前项和序列,记录到每一项时的权重是多少。然后随机生成一个数,可以用二分查找找这个数对应的索引,也就可以找到对应的元素。但是这样就要求数据不能存成字典,因为字典的遍历是无序的。

复制代码

import bisect
import random
data = {'A': 50, 'B': 10, 'C': 100, 'D': 3, 'E': 60, 'F': 25}
key_list = list(data.keys())
value_list = [data[key] for key in key_list]
prefix_sum = []
tmp_sum = 0
for value in value_list:
tmp_sum += value
prefix_sum.append(tmp_sum)
t = random.randint(0, tmp_sum - 1)
pick_value = key_list[bisect.bisect_right(prefix_sum, t)]

复制代码

同样统计结果如下

最后

以上就是明理秀发为你收集整理的根据权重生成随机数的全部内容,希望文章能够帮你解决根据权重生成随机数所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部