python的random模块及加权随机算法的python实现方法

作者:jingxian 时间:2023-09-04 13:32:57 

random是用于生成随机数的,我们可以利用它随机生成数字或者选择字符串。

•random.seed(x)改变随机数生成器的种子seed。

一般不必特别去设定seed,Python会自动选择seed。

•random.random()    用于生成一个随机浮点数n,0 <= n < 1

•random.uniform(a,b)    用于生成一个指定范围内的随机浮点数,生成的随机整数a<=n<=b;

•random.randint(a,b)    用于生成一个指定范围内的整数,a为下限,b为上限,生成的随机整数a<=n<=b;若a=b,则n=a;若a>b,报错

•random.randrange([start], stop [,step])    从指定范围[start,stop)内,按指定基数递增的集合中获取一个随机数,基数缺省值为1

•random.choice(sequence)    从序列中获取一个随机元素,参数sequence表示一个有序类型,并不是一种特定类型,泛指list,tuple,字符串等

•random.shuffle(x[,random])    用于将一个列表中的元素打乱 (洗牌),会改变原始列表

•random.sample(sequence,k)    从指定序列中随机获取k个元素作为一个片段返回,不会改变原有序列

那么现在基础知识有了,我们来实现一个加权随机算法:

加权随机算法一般应用在以下场景:有一个集合S,里面比如有A,B,C,D这四项。这时我们想随机从中抽取一项,但是抽取的概率不同,比如我们希望抽到A的概率是50%,抽到B和C的概率是20%,D的概率是10%。一般来说,我们可以给各项附一个权重,抽取的概率正比于这个权重。那么上述集合就成了:

{A:5,B:2,C:2,D:1}

方法一:

最简单的方法可以这样:

把序列按权重值扩展成:lists=[A,A,A,A,A,B,B,C,C,D],然后random.choice(lists)随机选一个就行。虽然这样选取的时间复杂度是O(1),但是数据量一大,空间消耗就太大了。


# coding:utf-8
import random

def weight_choice(list, weight):
 """
 :param list: 待选取序列
 :param weight: list对应的权重序列
 :return:选取的值
 """
 new_list = []
 for i, val in enumerate(list):
   new_list.extend(val * weight[i])
 return random.choice(new_list)

if __name__ == "__main__":
 print(weight_choice(['A', 'B', 'C', 'D'], [5, 2, 2, 1]))

方法二:

比较常用的方法是这样:

计算权重总和sum,然后在1到sum之间随机选择一个数R,之后遍历整个集合,统计遍历的项的权重之和,如果大于等于R,就停止遍历,选择遇到的项。

还是以上面的集合为例,sum等于10,如果随机到1-5,则会在遍历第一个数字的时候就退出遍历。符合所选取的概率。

选取的时候要遍历集合,它的时间复杂度是O(n)。


# coding:utf-8
import random

list = ['A', 'B', 'C', 'D']

def weight_choice(weight):
 """
 :param weight: list对应的权重序列
 :return:选取的值在原列表里的索引
 """
 t = random.randint(0, sum(weight) - 1)
 for i, val in enumerate(weight):
   t -= val
   if t < 0:
     return i

if __name__ == "__main__":
 print(list[weight_choice([5, 2, 2, 1])])

方法三:

可以先对原始序列按照权重排序。这样遍历的时候,概率高的项可以很快遇到,减少遍历的项。(因为rnd递减的速度最快(先减去最大的数))

比较{A:5,B:2,C:2,D:1}和{B:2,C:2,A:5,D:1}

前者遍历步数的期望是5/10*1+2/10*2+2/10*3+1/10*4=19/10而后者是2/10*1+2/10*2+5/10*3+1/10*4=25/10。

这样提高了平均选取速度,但是原序列排序也需要时间。

先搞一个权重值的前缀和序列,然后在生成一个随机数t后,可以用二分法来从这个前缀和序列里找,那么选取的时间复杂度就是O(logn)了。

 


# coding:utf-8
import random
import bisect

list = ['A', 'B', 'C', 'D']

def weight_choice(weight):
 """
 :param weight: list对应的权重序列
 :return:选取的值在原列表里的索引
 """
 weight_sum = []
 sum = 0
 for a in weight:
   sum += a
   weight_sum.append(sum)
 t = random.randint(0, sum - 1)
 return bisect.bisect_right(weight_sum, t)

if __name__ == "__main__":
 print(list[weight_choice([5, 2, 2, 1])])
标签:加权随机,算法,python,random
0
投稿

猜你喜欢

  • 仿vue-cli搭建属于自己的脚手架的方法步骤

    2024-05-21 10:18:09
  • python画双y轴图像的示例代码

    2021-12-07 16:07:12
  • 使用Python机器学习降低静态日志噪声

    2021-11-09 23:48:57
  • Python使用matplotlib绘制三维图形示例

    2022-09-14 10:53:14
  • 19个ASP编程基础典型代码

    2008-10-23 15:46:00
  • js验证表单(form)中多选框(checkbox)值

    2008-03-18 13:39:00
  • Python提高运行速度工具之Pandarallel的使用教程

    2021-07-16 20:14:09
  • windows下python和pip安装教程

    2022-04-07 13:00:44
  • 构建可视化 web的 Python 神器streamlit

    2021-05-03 16:56:05
  • asp fso创建与删除文件与文件夹

    2008-12-31 16:07:00
  • Python3.5 Pandas模块之Series用法实例分析

    2022-07-23 16:19:09
  • INPUT的对齐问题

    2008-05-24 08:32:00
  • Python多线程实例教程

    2022-11-30 14:15:43
  • python基础教程项目二之画幅好画

    2023-09-10 05:06:32
  • MySQL Community Server 8.0.11安装配置方法图文教程

    2024-01-26 06:02:45
  • python实现自动登录

    2023-10-20 05:11:46
  • 把pandas转换int型为str型的方法

    2022-02-16 15:45:03
  • Golang 单元测试和基准测试实例详解

    2024-05-05 09:27:58
  • Git文件常用操作总结及拓展

    2023-02-04 08:13:18
  • 基于Python实现商场抽奖小系统

    2021-07-01 14:46:14
  • asp之家 网络编程 m.aspxhome.com