700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Python 标准库之 random 生成伪随机数『详细』

Python 标准库之 random 生成伪随机数『详细』

时间:2023-01-16 22:13:52

相关推荐

Python 标准库之 random 生成伪随机数『详细』

Python 标准库之 random 生成伪随机数

文章目录

Python 标准库之 random 生成伪随机数一、Python random介绍🤪二、导入 random 库三、随机整数四、序列用随机函数五、实值分布六、random 可以做什么?🤔扩展:Python的集合也能实现随机扩展:为什么说 random 是伪随机数参考资料💌相关博客😏

一、Python random介绍🤪

random模块实现了各种分布的伪随机数生成器,对于整数,从范围中有统一的选择。 对于序列,存在随机元素的统一选择、用于生成列表的随机排列的函数、以及用于随机抽样而无需替换的函数。

本文章内容较多,如果需要查找某个特定的方法或属性,建议使用浏览器的查找ctrl + f功能

二、导入 random 库

在看下列内容前,别忘记导入random标准库呀

import random

三、随机整数

1)、random.randrange(start, stop[, step]):

.randrange(start, stop[, step])相当于.choice(range(start, stop, step)),也就是内置函数range()和方法choice()的结合,但实际上并没有构建一个 range 对象,位置参数模式匹配 range()

演示代码:

res1 = random.randrange(1, 11)# 1 - 10范围内的随机整数res2 = random.randrange(1, 11, 2) # 1 - 10范围内每两个的随机整数res3 = random.choice(range(1, 11, 2)) # 1 - 10范围内每两个的随机整数print(res1, res2, res3)

2)、random.randint(a, b):「常用」

a <= N <= b范围内返回整数N,此方法又相当于.randrange(a, b+1),简单点理解范围即是range(a, b+1)然后再从里面随机抽出一个整数

.randrange(start, stop[, step])的主要差别是有没有 步长 参数

演示代码:

res1 = random.randint(1, 10) # 1 - 10范围内的随机整数res2 = random.randrange(1, 11)# 1 - 10范围内的随机整数print(res1, res2)

四、序列用随机函数

1)、random.choice(seq):「常用」

从非空序列 seq 返回一个随机元素

演示代码:

res1 = random.choice(range(1, 11)) # 1 - 10范围内的随机整数res2 = random.choice(["张三", "李四", "王五", "罗翔", "Alex", "Jone"])print(res1, res2)

如果 seq 为空,则引发 IndexError

2)、random.choices(population, weights=None, cum_weights=None, k=1):

用于有重复的随机抽样,因此不能用作于类似抽奖的用途,返回包含来自population序列中元素组成的新列表,新列表的长度以K决定,如果需要无重复的随机抽样,参考.sample()方法

参数如下:

population:population(总体),从population中选择抽取,返回大小为 k 的元素列表

weights:如果给出了 weight 序列,则根据相对权重进行选择,如:[10, 5, 30, 5],在进行选择之前相对权重会转化为累计权重

cum_weights:如果给出了 cum_weights 序列,则根据绝对权重进行选择,相对权重[10, 5, 30, 5]相当于累积权重[10, 15, 45, 50],直接提供累计权重可以减少 内部代码的工作量

k:随机选取的元素 长度、数量

如果既未指定 weight 也未指定 cum_weights ,则以相等的概率进行选择。如果提供了权重序列,则它必须与 population 序列的长度相同。

演示代码:

arr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone"]# 随机选取列表中三元素res1 = random.choices(arr, k=3)# 随机选取列表中三元素, Jone 和 罗翔 被选取的概率最大res2 = random.choices(arr, weights=[5, 10, 30, 25, 15, 30], k=3)# 随机选取列表中三元素,累计权重概率与上面相对权重相等,Jone 和 罗翔 被选取的概率最大res3 = random.choices(arr, cum_weights=[5, 15, 45, 70, 85, 115], k=3)print(res1, res2, res3)

如果 population 为空,则引发 IndexError

3)、random.shuffle(x[, random]):「常用」

shuffle 有着洗牌的意思,该方法主要作用是将一个序列中的元素打乱重新排列

源码:

def shuffle(self, x, random=None):"""Shuffle list x in place, and return None.Optional argument random is a 0-argument function returning arandom float in [0.0, 1.0); if it is the default None, thestandard random.random will be used."""if random is None:randbelow = self._randbelowfor i in reversed(range(1, len(x))):# pick an element in x[:i+1] with which to exchange x[i]j = randbelow(i+1)x[i], x[j] = x[j], x[i]else:_int = intfor i in reversed(range(1, len(x))):# pick an element in x[:i+1] with which to exchange x[i]j = _int(random() * (i+1))x[i], x[j] = x[j], x[i]

参数如下:

x:将序列 x 随机打乱位置random:可选参数 random 是一个函数,在 [0.0, 1.0) 中返回随机浮点数,如果不指定将默认使用.random()方法

演示代码:

arr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone"]print(arr) # 打印原数组random.shuffle(arr)print(arr) # 打印随机后数组

4)、random.sample(population, k):「常用」

用于无重复的随机抽样,因此能用作于类似抽奖的用途,返回包含来自population序列中元素组成的新列表,新列表的长度以K决定,如果需要有重复的随机抽样,参考.choices()方法

参数如下:

population:population(总体),从population中选择抽取,返回大小为 k 的元素列表k:返回从总体序列或集合中选择的唯一元素的数量、长度

演示代码:

简易抽奖示例

arr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone"]res = random.sample(arr, 3)level = {1: "一等奖", 2: "二等级", 3: "三等奖"}for i, k in enumerate(res, 1):print(f"{level[i]}: {k}", end=" ")

如果样本大小大于总体大小,则引发 ValueError

五、实值分布

以下函数生成特定的实值分布。如常用数学实践中所使用的那样, 函数参数以分布方程中的相应变量命名;大多数这些方程都可以在任何统计学教材中找到

1)、random.random():

返回[0.0, 1.0)范围内的下一个随机浮点数,精确到小数点后16位

演示代码:

for i in range(10):print(round(random.random(), 5)) # 四舍五入精确到后五位

2)、random.uniform(a, b):

返回一个随机浮点数 N ,当a <= ba <= N <= b,当b < ab <= N <= a,精确到小数点后16位

简单来说就是返回 a 和 b 之间,包括a 和 b 的一个浮点数,最小范围是 a 和 b 中最小的,最大范围是 a 和 b 中最大的

源码:

源码其实很简单,算法就是公式a + (b-a) * self.random()

def uniform(self, a, b):"Get a random number in the range [a, b) or [a, b] depending on rounding."return a + (b-a) * self.random()

演示代码:

res1 = random.uniform(10, 1) # 返回 1 <= N <= 10 之间的浮点数res2 = random.uniform(1, 10) # 返回 1 <= N <= 10 之间的浮点数res3 = 1 + (10-1) * random.random() # 返回 1 <= N <= 10 之间的浮点数print(res1, res2, res3, sep=r" // ")

3)、random.triangular(low, high, mode):

返回一个随机浮点数 N ,使得low <= N <= high并在这些边界之间使用指定的mode

源码:

def triangular(self, low=0.0, high=1.0, mode=None):"""Triangular distribution.Continuous distribution bounded by given lower and upper limits,and having a given mode value in-between./wiki/Triangular_distribution"""u = self.random()try:c = 0.5 if mode is None else (mode - low) / (high - low)except ZeroDivisionError:return lowif u > c:u = 1.0 - uc = 1.0 - clow, high = high, lowreturn low + (high - low) * _sqrt(u * c)

参数如下:

low:返回随机浮点数 N 的最小值,默认值为 0high:返回随机浮点数 N 的最大值,默认值为 1mode:通过源码可以得知对 mode 的处理0.5 if mode is None else (mode - low) / (high - low),默认值为 0.5 为边界之间的中点,给出对称分布

演示代码:

arr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone"]low, high, mode = 0, 5, 5c = (mode - low) / (high - low)res1 = random.triangular(low, high)res2 = random.triangular(low, high, mode=mode)print(c, res1, res2, sep=r" // ")

4)、random.betavariate(alpha, beta):「了解」

Beta 分布,又称贝塔分布,参数的条件是alpha > 0beta > 0, 返回值的范围介于 0 和 1 之间

概率密度函数

演示代码:

res1 = random.betavariate(2, 2)res2 = random.betavariate(0.5, 0.5)res3 = random.betavariate(5, 1)print(res1, res2, res3, sep=r" // ")

5)、random.expovariate(lambd):「了解」

指数分布,该参数本应命名为lambda,但这是 Python 中的保留字

如果 lambd 为正,则返回值的范围为 0 到正无穷大;如果 lambd 为负,则返回值从负无穷大到 0

演示代码:

res1 = random.expovariate(1)res2 = random.expovariate(-1)print(res1, res2, sep=r" // ")

6)、random.gammavariate(alpha, beta):「了解」

Gamma 分布,参数的条件是alpha > 0beta > 0

概率分布公式是:👇🏻

演示代码:

res1 = random.gammavariate(5, 1)res2 = random.gammavariate(1, 6)res3 = random.gammavariate(6, 6)print(res1, res2, res3, sep=r" // ")

7)、random.gauss(mu, sigma):「了解」

高斯分布, mu 是平均值,sigma 是标准差,这比下面要讲的 normalvariate() 函数略快

正态分布(台湾作常态分布,英语:normal distribution)又名高斯分布(英语:Gaussian distribution)、正规分布,是一个非常常见的连续概率分布,正态分布在统计学上十分重要,经常用在自然和社会科学来代表一个不明的随机变量

概率密度函数

红线代表标准正态分配

演示代码:

res1 = random.gauss(0, 0.2)res2 = random.gauss(0, 1)res3 = random.gauss(0, 5)res4 = random.gauss(-2, 0.5)print(res1, res2, res3, res4, sep=r" \\ ")

8)、random.lognormvariate(mu, sigma):「了解」

任意随机变量的对数服从正态分布,则这个随机变量服从的分布称为对数正态分布,如果你采用这个分布的自然对数,你将得到一个正态分布

平均值为 mu 和标准差为 sigma,mu 可以是任何值,sigma 必须大于零

μ=0 概率密度函数

演示代码:

res1 = random.lognormvariate(0, 10)res2 = random.lognormvariate(0, 1)res3 = random.lognormvariate(0, 0.5)res4 = random.lognormvariate(0, 0.25)print(res1, res2, res3, res4, sep=r" \\ ")

9)、random.normalvariate(mu, sigma):「了解」

正态分布,mu 是平均值,sigma 是标准差,具体参考7)、random.gauss(mu, sigma)

演示代码:

res1 = random.normalvariate(0, 0.2)res2 = random.normalvariate(0, 1)res3 = random.normalvariate(0, 5)res4 = random.normalvariate(-2, 0.5)print(res1, res2, res3, res4, sep=r" \\ ")

10)、random.vonmisesvariate(mu, kappa):「了解」

冯·米塞斯(von Mises)分布,mu 是平均角度,以弧度表示,介于0和 2*pi 之间,kappa 是浓度参数,必须大于或等于零

如果 kappa 等于零,则该分布在 0 到 2*pi 的范围内减小到均匀的随机角度

演示代码:

res1 = random.vonmisesvariate(6, 0)res2 = random.vonmisesvariate(6, 1)res3 = random.vonmisesvariate(6, 6)res4 = random.vonmisesvariate(90, 0)print(res1, res2, res3, res4, sep=r" \\ ")

11)、random.paretovariate(alpha):「了解」

帕累托分布(Pareto distribution)是以意大利经济学家维尔弗雷多·帕累托命名的,alpha 是形状参数

概率密度函数

演示代码:

res1 = random.paretovariate(1)res2 = random.paretovariate(2)res3 = random.paretovariate(3)print(res1, res2, res3, sep=r" \\ ")

12)、random.weibullvariate(alpha, beta):「了解」

威布尔分布(Weibull distribution)是可靠性分析和寿命检验的理论基础,alpha 是比例参数,beta 是形状参数

概率密度函数

演示代码:

res1 = random.weibullvariate(1, 0.5)res2 = random.weibullvariate(1, 1)res3 = random.weibullvariate(1, 1.5)res4 = random.weibullvariate(1, 5)print(res1, res2, res3, res4, sep=r" \\ ")

六、random 可以做什么?🤔

random 的中文释义是 随机的 意思,那顾名思义干的就是一些随机的活

1)、抽个奖压压惊

抽奖类问题是 随机 最常见的实际应用之一,在上面的方法演示中也提到过了抽奖

a. 先来看看常见思维的写法,循环需要的奖项,在每次循环中将其进行抽取各奖项的获奖者

def get_winners(items: list, level: dict):"""抽取获奖者传统思维写法:param items: 参与人员列表:param level: 获奖级别信息:return: 获奖结果"""res = {}for i in level.keys():item = random.sample(arr, level[i]) # 随机选取指定数量的元素for d in item: # 遍历选取结果并删除items.remove(d)res[i] = item# 添加到结果字典中return resarr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone", "Mark", "李华", "全蛋", "铁花"]win_level = {"一等奖": 1, "二等奖": 3, "三等奖": 5}print(get_winners(arr, win_level))

b. 在上面介绍过random.sample(population, k)方法,它是无重复随机抽样,运用这个无重复一次性把所有获奖抽出,再以前后顺序确定奖项即可

def get_winners(items: list, level: dict):"""抽取获奖者以索引取法:param items: 参与人员列表:param level: 获奖级别信息:return: 获奖结果"""target = random.sample(items, sum(level.values()))res, prev = {}, 0for i in level.keys():res[i] = target[prev: level[i] + prev]prev += level[i]return resarr = ["张三", "李四", "王五", "罗翔", "Alex", "Jone", "Mark", "李华", "全蛋", "铁花"]win_level = {"一等奖": 1, "二等奖": 3, "三等奖": 5}print(get_winners(arr, win_level))

2)、猜号数

学习 Python 的同学很多都有接触过这个题目,猜号数问题算是最基础的 Python题目之一,这里咱就复习一下

a. 生成一个 1~100之间的随机数,判断用户输入的数值是否与生成的随机数想等,如果大于这个值或小于这个值,应当提醒用户

其中c_print()函数作用用于颜色打印,详情可以参考我关于 颜色打印 的文章

def fuess_the_number():"""猜数字小游戏, 无限制次数"""target = random.randint(1, 100)# 生成需要猜的目标值while True:enter = input("请输入需要您所猜的值:")if not enter.isdigit():# 判断是否为数字c_print("请输入整数", color=31)elif not (100 >= (enter := int(enter)) >= 1):# 判断范围是否在 1-100 之间c_print("请输入100-1之间的值", color=31)else:if enter > target:c_print("数值太大啦[再试试]", color=36)elif enter < target:c_print("数值太小啦[再试试]", color=36)else:c_print("Bingo, 答对了")break

b. 在上述问题的基础上,自定义最大可尝试次数,更改量其实很少

def fuess_the_number(max_try: int):"""猜数字小游戏, 无限制次数"""target = random.randint(1, 100) # 生成需要猜的目标值for _ in range(max_try):enter = input("请输入需要您所猜的值:")if not enter.isdigit():# 判断是否为数字c_print("请输入整数", color=31)elif not (100 >= (enter := int(enter)) >= 1):# 判断范围是否在 1-100 之间c_print("请输入100-1之间的值", color=31)else:if enter > target:c_print("数值太大啦[再试试]", color=36)elif enter < target:c_print("数值太小啦[再试试]", color=36)else:c_print("Bingo, 答对了")breakelse:c_print("很遗憾您并没有猜出来, 挑战结束", color=36)fuess_the_number(5)

在限定次数中,我将错误检测也算进了可猜次数中,这里我留下这个坑,有兴趣的同学可以自己去试试做出更改

3)、发个牌

相信大多数人都打过扑克牌吧,我就没打过🙄写这之前还去查了一下组合,发牌类问题是 随机 最常见的实际应用之一,大家可以先去尝试编写一个利用random随机发牌的小程序

52张正牌又均分为13张一组,并以黑桃、红桃、梅花、方块四种花色表示各组,每组花色的牌包括从1-10(1通常表示为A)以及J、Q、K标示的13张牌

花色:["梅花", "方片", "红桃", "黑桃"]牌面数字:["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]

class Card:def __init__(self):self.card_color = ["梅花", "方片", "红桃", "黑桃"]self.card_nums = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]self.cards = self.init_card()# 获取初始牌组合def init_card(self):"""初始牌组合方法:return: 组合牌"""cards = []for i in self.card_color:cards.extend([f"{i}{k}" for k in self.card_nums])return cardsdef shuffle_card(self, shu_num=1):"""洗牌方法:param shu_num: 洗牌次数, 默认为1:return: 洗后牌"""for _ in range(shu_num):random.shuffle(self.cards)return self.cardsdef deal_card(self, items: list or tuple):"""发牌方法:param items: 玩家成员 :return: 每个成员所发的牌"""if not isinstance(items, (list, tuple)):raise TypeError("成员信息应以列表或元组传入")elif (length := len(items)) > 4:raise Exception("成员过多")dic, prev, random_res = {}, 0, random.sample(self.cards, length*13)for i in items:# prev 为索引指针dic[i] = random_res[prev:prev+14]prev += 14return dic

play = Card() # 实例化游戏对象play.shuffle_card(5) # 洗牌5次player = play.deal_card( # 添加玩家发牌["张三", "罗翔"])

{'张三': ['梅花7', '黑桃K', '红桃8', '方片A', '方片7', '梅花2', '梅花5', '黑桃2', '方片3', '红桃A', '梅花6', '红桃5', '黑桃9', '黑桃4'], '罗翔': ['红桃2', '红桃Q', '梅花3', '红桃6', '红桃J', '黑桃A', '方片8', '梅花4', '方片5', '黑桃5', '红桃K', '梅花Q']}

4)、画个雪花玩玩「大型运用」

说到画图,印象较深的就是Python的海龟库turtle,这是大多数Python学习者初期所接触到的标准库,我将使用turple进行图像绘画

画雪花使用random的次数绝对够多,雪花的大小,雪花的粗细,雪花的位置,这些都是需要考虑随机的东西,因此可以在示例代码中能够见到多次random的身影

def draw_snow(min_size, max_size, color=True):"""绘画雪花函数:param min_size: 最小雪花长度:param max_size: 最大雪花长度:param color: 是否随机颜色, 默认为是"""t.pendown()if color is True:# 颜色模式改成255, 并随机rgb颜色t.colormode(255)rgb = [random.randint(0, 255) for _ in range(3)]t.pencolor((rgb[0], rgb[1], rgb[2]))else:t.pencolor("white")snowsize = random.randint(min_size, max_size)side = snowsize // 2# 边数for _ in range(side):t.forward(snowsize)t.backward(snowsize)t.right(360 / side)t.penup()def draw(quantity, x, y):"""主画图:param quantity: 雪花数量:param x: 窗口宽度大小:param y: 窗口高度大小"""t.ht() # 隐藏海龟t.setup(x, y, 500, 250) # 设置窗口大小t.bgcolor("black") # 设置背景色t.tracer(False)# 关闭海龟动画t.title("雪花图")for _ in range(quantity):t.penup()# 获取x轴与y轴雪花范围x_range = random.randint(-(x//2-50), (x//2-50))y_range = random.randint(-(y//2-50), (y//2-50))t.pensize(random.randint(1, 3))# 1-3 画笔随机大小t.goto(x_range, y_range) # 移动画笔draw_snow(15, 30) # 调用画雪花t.exitonclick()# 鼠标点击后关闭窗口if __name__ == '__main__':draw(100, 800, 500)

扩展:Python的集合也能实现随机

集合的 .pop() 方法

从集合中移除并返回任意一个元素,其实就是随机移除一个元素并返回

如果集合为空则会引发 KeyError,可以先判断集合是否为空

需要注意的是,集合的.pop方法的随即效果只针对字符串有效,如果是数字类型每次移除并返回的都是同一个元素,详情请移步我关于集合的文章

还是以随机抽奖为例👇🏻

s_user = {"张三", "李四", "小美", "王华", "小明", "李华"}awarded = []while len(awarded) < 3:awarded.append(s_user.pop())print(f"获奖用户: {' '.join(awarded)}")

扩展:为什么说 random 是伪随机数

的近义词是,有着假的意思,那么伪随机数又指的是什么意思呢?

我们先来看看官方手册对伪随机数的描述:👇🏻

Python 使用 Mersenne Twister 作为核心生成器。 它产生 53 位精度浮点数,周期为 2**19937-1 ,其在 C 中的底层实现既快又线程安全。 Mersenne Twister 是现存最广泛测试的随机数发生器之一。但是,因为完全确定性,它不适用于所有目的,并且完全不适合加密目的警告 不应将此模块的伪随机生成器用于安全目的。 有关安全性或加密用途,请参阅 secrets 模块。,在random手册下另外还有这一句话,看来想要知道这个伪是什么意思,我们得进一步的查看secrets标准库模块下的手册

secrets手册下 又有着这么一句话特别地,应当优先使用 secrets 来替代 random 模块中的默认伪随机数生成器,后者被设计用于建模和仿真,而不适用于安全和加密。

如果好奇心爆棚,可以去看看 PEP 506 对此的描述,简单来说使用 random 随机的结果是有一定规律可循的,有一定漏洞的随机数

参考资料💌

维基百科中文版:

序列Βeta分布、贝塔分布指数分布伽玛分布、Gamma 分布正态分布、高斯分布对数正态分布

Python 官方手册:

random 生成伪随机数

由衷感谢💖

相关博客😏

Python 有趣ヾ(≧▽≦*)o SET 集合类型Python 如何让打印内容变得优雅(颜色打印)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。