- 示例工程
- 教程
【免费下载链接】materials
Bonus materials, exercises, and example projects for our Python tutorials
导读
本文以 numpy-rng 目录中的配套代码为线索,系统讲解 NumPy 伪随机数生成器(Pseudo-Random Number Generator,PRNG)的新一代GeneratorAPI 用法。从环境搭建、基础采样到多维数组生成、洗牌与排列、位生成器(BitGenerator)与种子管理,再到泊松分布建模,读者可以对照仓库中的 19 个源码文件,一步步掌握np.random.default_rng()的完整工作流,并理解其与旧版np.random.seed()体系的差异。读完本文,你将能够用 NumPy 生成可复现的随机整数、随机浮点数、随机抽样、打乱数组以及符合特定概率分布的样本,并借助 matplotlib 与 SciPy 验证统计结果。
环境准备:创建虚拟环境并安装依赖
numpy-rng/README.md 给出了标准的复现步骤:先创建并激活虚拟环境,再安装依赖。
$ python -m venv venv $ source venv/bin/activate (venv) $ python -m pip install -r requirements.txt -c constraints.txt其中两份依赖文件分工明确:
numpy-rng/requirements.txt 声明了最小依赖集合:
numpy>=1.17 scipy matplotlibnumpy>=1.17是使用新版GeneratorAPI 的最低版本门槛,scipy与matplotlib则用于本文最后一节泊松分布的解析计算与绘图。numpy-rng/constraints.txt 通过
-c参数以约束(constraints)方式固定了经过测试的精确版本(如numpy==1.24.3、scipy==1.10.1、matplotlib==3.7.1)。约束文件只锁定版本而非声明直接依赖,因而在保持环境可复现的同时,不会覆盖其他包的传递依赖解析。
装好依赖后,每个示例文件都可以独立运行:
(venv) $ python filename.py例如直接运行入门示例:
(venv) $ python default_rng.py新版随机数入口:np.random.default_rng()
NumPy 1.17 起引入了基于Generator的新一代随机数体系,其推荐入口就是np.random.default_rng()。仓库的 numpy-rng/default_rng.py 是最简示例:
import numpy as np default_rng = np.random.default_rng() print(default_rng) print(default_rng.random())运行后会先打印生成器对象信息(其中包含默认位生成器PCG64及随机种子),再输出一个[0, 1)区间的随机浮点数。
与旧版np.random全局函数式接口相比,default_rng()有两点核心差异:
- 对象式设计:每次调用
default_rng()都会得到独立的Generator实例,其内部状态与全局np.random互不干扰,天然适合并发与多模块场景; - 默认位生成器升级:默认使用
PCG64(而不是旧版的MT19937梅森旋转),随机性统计质量更好,且支持流式并行。
Generator上的常用方法在旧接口中基本都能找到对应物,例如:
Generator方法 | 对应旧接口 | 用途 |
|---|---|---|
rng.integers() | np.random.randint() | 随机整数 |
rng.random() | np.random.random_sample() | [0, 1)均匀浮点数 |
rng.uniform() | np.random.uniform() | 指定区间的均匀分布 |
rng.choice() | np.random.choice() | 从数组中随机抽取 |
rng.shuffle() | np.random.shuffle() | 原地打乱数组 |
rng.permutation() | np.random.permutation() | 返回打乱后的副本 |
rng.poisson() | np.random.poisson() | 泊松分布采样 |
生成随机整数:integers()的边界语义
numpy-rng/integers.py 集中演示了integers()在不同参数下的行为:
import numpy as np rng = np.random.default_rng() for i in range(5): print(rng.integers(3)) # 等价于 rng.integers(low=0, high=3) for count in range(5): print(rng.integers(low=1, high=4)) for count in range(5): print(rng.integers(low=7)) for count in range(5): print(rng.integers(low=1, high=4, endpoint=True)) for count in range(5): print(rng.integers(low=7, endpoint=True))关键参数语义如下:
low与high:采样区间为[low, high),包含low但不包含high(与旧版randint一致)。所以rng.integers(3)只可能返回0、1、2,rng.integers(low=1, high=4)只可能返回1、2、3;- 只传一个参数时,它被视为
high,low默认取0,因此rng.integers(low=7)返回[0, 7)内的整数; endpoint=True会把上界改为包含,即rng.integers(low=1, high=4, endpoint=True)的取值范围扩展为1、2、3、4,rng.integers(low=7, endpoint=True)则返回0~7共 8 个可能值。
此外integers()还支持size参数批量生成数组(参见 numpy-rng/array_constraints.py 中的rng.integers(size=(2, 2), low=1, high=5)),返回的是[1, 5)内均匀分布的2×2整数矩阵。
生成随机数组:random()与多维size
numpy-rng/arrays.py 展示了如何一次性生成任意形状的[0, 1)均匀浮点数数组:
import numpy as np rng = np.random.default_rng() print(rng.random(size=(5,))) print(rng.random(size=(5, 3))) print(rng.random(size=(3, 4, 2)))size=(5,)返回长度为 5 的一维数组;size=(5, 3)返回5×3的二维数组;size=(3, 4, 2)返回三维数组,共3×4×2 = 24个样本。
size接受任意正整数形状元组,是构造随机数据、初始化权重矩阵(如神经网络参数)的常用手段。
指定区间的浮点数:uniform()
numpy-rng/uniform_for_floats.py 演示了如何把均匀分布限定到指定区间:
import numpy as np rng = np.random.default_rng() print(rng.uniform()) print(rng.uniform(low=3.4, high=5.6))- 不带参数时
rng.uniform()等价于rng.random(),返回[0, 1)的浮点数; rng.uniform(low=3.4, high=5.6)返回[3.4, 5.6)区间内均匀分布的浮点数。
与整数接口一致,uniform()也支持size参数,例如rng.uniform(size=(2, 2), low=1, high=5)(见 numpy-rng/array_constraints.py)会生成一个2×2的均匀浮点矩阵。
从数组中随机抽取:choice()与shuffle参数
一维数组的无放回抽样
numpy-rng/choice.py 演示了从一维数组中随机选择:
import numpy as np rng = np.random.default_rng() input_array_1d = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) print(rng.choice(input_array_1d, size=3, replace=False)) print(rng.choice(input_array_1d, size=(2, 3), replace=False))size=3, replace=False:无放回抽取 3 个互不重复的元素;size=(2, 3), replace=False:抽取结果排列成2×3的形状(每个样本仍来自原数组的一次无放回选择,整体构成一个含 6 个不重复元素的抽样结果)。
replace=False要求size不超过数组长度;若想允许重复,则使用replace=True(默认行为)。
二维数组与axis、shuffle参数
numpy-rng/choice_shuffle.py 把案例扩展到二维数组,并展示了 NumPy 1.24 新增的shuffle参数:
import numpy as np input_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) rng = np.random.default_rng() print(rng.choice(input_array, size=2)) # 沿 axis=0 抽取 2 行 print(rng.choice(input_array, size=2, axis=1)) # 沿 axis=1 抽取 2 列 print(rng.choice(input_array, size=3, replace=False)) # 无放回抽取 3 行 rng = np.random.default_rng(seed=100) print(rng.choice(input_array, size=3, replace=False, shuffle=False)) rng = np.random.default_rng(seed=100) print(rng.choice(input_array, size=3, replace=False, shuffle=True)) rng = np.random.default_rng(seed=100) print(rng.choice(input_array, size=3, replace=True, shuffle=False)) rng = np.random.default_rng(seed=100) print(rng.choice(input_array, size=3, replace=True, shuffle=True))要点说明:
- 默认沿
axis=0抽取(对二维数组即抽取整行),axis=1则沿列方向抽取; shuffle参数控制抽样结果的排列方式:shuffle=True时抽样结果在内部被打乱后再返回,shuffle=False时则保持抽取顺序。两种模式下样本集合相同,只是返回顺序不同;- 从源码可以看出,相同
seed=100下分别用shuffle=False与shuffle=True调用,打印结果会呈现"集合相同、顺序不同"的差异,这正是该参数存在的意义——当后续步骤依赖抽样结果的原始顺序时,应使用shuffle=False。
打乱与排列:shuffle()、permutation()与permuted()
用扑克牌案例理解三种方法
仓库用扑克牌数据构造了直观的演示场景。numpy-rng/decks.py 提供两个辅助函数:
import numpy as np def create_deck(): RANKS = "2 3 4 5 6 7 8 9 10 J Q K A".split() SUITS = "♣ ♢ ♡ ♠".split() return np.array([r + s for s in SUITS for r in RANKS]) def create_high_cards(): HIGH_CARDS = "10 J Q K A".split() SUITS = "♣ ♢ ♡ ♠".split() return np.array([r + s for s in SUITS for r in HIGH_CARDS])create_deck()生成一副 52 张牌的数组(按花色排列),create_high_cards()则生成只含10 J Q K A的 20 张"高牌"数组。
shuffle():原地打乱
numpy-rng/shuffle.py 演示原地洗牌:
import numpy as np from decks import create_deck rng = np.random.default_rng() deck_of_cards = create_deck() rng.shuffle(deck_of_cards) print(deck_of_cards[0:3]) rng.shuffle(deck_of_cards) print(deck_of_cards[0:3])rng.shuffle()会直接修改传入数组(原地操作,返回None),连续调用两次洗牌,每次牌面顺序都不同。注意:旧版np.random.shuffle()只支持一维数组,而新版Generator.shuffle()通过axis参数支持多维数组,例如 numpy-rng/permutation_vs_shuffle.py 中的rng.shuffle(high_deck, axis=0)与rng.shuffle(high_deck, axis=1)分别沿行、列方向原地打乱。
permutation():返回打乱后的副本
numpy-rng/permutation_vs_shuffle.py 对照演示了permutation()与shuffle()的关键差异:
import numpy as np from decks import create_high_cards NUMBER_OF_SUITES = 4 NUMBER_OF_RANKS = 5 rng = np.random.default_rng() high_deck = create_high_cards().reshape((NUMBER_OF_SUITES, NUMBER_OF_RANKS)) print(rng.permutation(high_deck, axis=0)) # 打乱行,不修改原数组 print(rng.permutation(high_deck, axis=0)) print(rng.permutation(high_deck, axis=1)) # 打乱列,不修改原数组 print(rng.permutation(high_deck, axis=1)) print(high_deck) # 原数组保持不变 rng.shuffle(high_deck, axis=0) # 原地打乱行 print(high_deck) rng.shuffle(high_deck, axis=1) # 原地打乱列 print(high_deck)(其中high_deck是一个4×5的"高牌"矩阵,每行一个花色、每列一个点数,构造过程见 numpy-rng/high_deck_example.py。)
对比结论:
permutation()返回打乱后的新数组副本,原数组保持不变(源码中连续调用多次后打印high_deck,其内容始终未变);shuffle()是原地操作,直接改写原数组;- 两者都支持
axis指定打乱方向:axis=0打乱行顺序,axis=1打乱列顺序。
permuted():独立洗刷每一轴
numpy-rng/permuted.py 介绍 NumPy 1.20 引入的permuted():
import numpy as np from decks import create_high_cards NUMBER_OF_SUITES = 4 NUMBER_OF_RANKS = 5 high_deck = create_high_cards().reshape((NUMBER_OF_SUITES, NUMBER_OF_RANKS)) rng = np.random.default_rng() print(rng.permuted(high_deck, axis=0)) # 逐列独立打乱行序 print(rng.permuted(high_deck, axis=1)) # 逐行独立打乱列序 print(rng.permuted(rng.permuted(high_deck, axis=1), axis=0)) # 先列后行与shuffle()、permutation()的关键区别在于:
permuted()是沿指定轴逐切片独立打乱。对axis=0,它会取出每一列,把这一列的 4 行各自独立地重新排列,各列之间互不影响;- 这与
shuffle(axis=0)(整行作为一个整体参与打乱,行内元素保持相对顺序)形成鲜明对比——后者打乱的是"行的排列",前者打乱的是"每一列内部的行序"。
位生成器(BitGenerator)与种子管理
显式构造:Generator+ 位生成器
新架构把"随机数引擎"(位生成器)与"分布采样"(Generator)分离。默认情况下default_rng()使用PCG64位生成器,而 numpy-rng/generator_swap_and_seeds.py 演示了显式组合方式:
from numpy.random import PCG64DXSM, Generator pcg64dxsm_rng = Generator(PCG64DXSM()) print(pcg64dxsm_rng.random()) rng1 = Generator(PCG64DXSM(seed=100)) print(rng1.random()) print(rng1.random()) rng2 = Generator(PCG64DXSM(seed=100)) print(rng2.random()) print(rng2.random())要点:
PCG64DXSM是PCG64的改进版本(使用 DXSM 乘法),提供更高质量的随机位输出;- 两个
seed=100的Generator实例会产出完全相同的随机数序列,这正是可复现实验的关键:只要种子一致,结果就可复现; - 位生成器决定底层随机位,
Generator决定如何把随机位映射为各分布样本,因此更换位生成器(如换成MT19937、Philox或SFC64)无需改动上层采样代码。
通过array_constraints.py认识多维约束
numpy-rng/array_constraints.py 同时使用了显式Generator(PCG64DXSM())与size参数:
from numpy.random import PCG64DXSM, Generator rng = Generator(PCG64DXSM()) print(rng.integers(size=(2, 2), low=1, high=5)) print(rng.uniform(size=(2, 2), low=1, high=5))这展示了位生成器 +Generator组合与旧式np.random全局接口在 API 上完全一致的使用体验,且支持批量形状参数。
泊松分布:从理论公式到随机采样
手工计算概率:cars_per_minute.py
numpy-rng/cars_per_minute.py 先用泊松分布的概率质量函数手工验证:
import math lam = 4 cars_per_minute = [0, 4, 8] for cars in cars_per_minute: probability = lam**cars * math.exp(-lam) / math.factorial(cars) print(f"P({cars}) = {probability:.1%}")场景设定为"平均每分钟有 4 辆车通过"(即lam = 4),公式P(k) = λᵏ·e⁻λ / k!给出每分钟恰好出现k辆车的概率:P(0) ≈ 1.8%,P(4) ≈ 19.5%,P(8) ≈ 2.9%。这个手算结果正是后续随机采样的理论参照。
随机采样:poisson.py
numpy-rng/poisson.py 用Generator.poisson()生成泊松样本:
import numpy as np rng = np.random.default_rng() scalar = rng.poisson(lam=5) print(scalar) sample_1d_array = rng.poisson(lam=5, size=4) print(sample_1d_array) sample_2d_array = rng.poisson(lam=5, size=(2, 3)) print(sample_2d_array)lam是泊松分布的均值参数(λ),也等于其方差;- 不传
size返回标量,size=4返回一维样本数组,size=(2, 3)返回二维样本矩阵; - 每个样本都是非负整数,围绕
lam波动,且分布越接近理论 PMF。
可视化验证:随机样本 vs 理论分布
仓库提供了两个绘图脚本,从两个角度交叉验证泊松分布:
numpy-rng/random_poisson_plot.py 对rng.poisson(lam=5, size=10_000)抽出的 10 000 个样本做频数统计并绘图:
import matplotlib.pyplot as plt import numpy as np rng = np.random.default_rng() samples = rng.poisson(lam=5, size=10_000) values, frequency = np.unique(samples, return_counts=True) plt.title("Random Poisson Distribution.") plt.xlabel("Values") plt.ylabel("Frequency") plt.plot(values, frequency, "ro") plt.show()numpy-rng/sample_poisson_plot.py 则用 SciPy 按理论公式计算λ = 4时k = 0…29的概率并绘图:
import matplotlib.pyplot as plt import numpy as np from scipy.special import factorial lam = 4 k_values = np.arange(0, 30) probabilities = np.power(lam, k_values) * np.exp(-lam) / factorial(k_values) plt.plot(k_values, probabilities, "ro") plt.title("Sample Poisson Distribution.") plt.xlabel("k") plt.ylabel("P(k)") plt.show()运行这两个脚本可以看到:随机采样的直方图形状与理论概率曲线高度吻合——这正是"随机数生成器忠实服从目标分布"的可视化证据,也解释了 README 中"在教程最后部分才会用到 matplotlib 和 scipy"的原因。
文件清单与运行路线
本节梳理 numpy-rng 目录的全部源码,便于按学习路径逐个运行:
| 文件 | 主题 | 运行方式 |
|---|---|---|
| default_rng.py | 新版随机数入口 | python default_rng.py |
| integers.py | 随机整数与边界语义 | python integers.py |
| arrays.py | 多维随机数组 | python arrays.py |
| uniform_for_floats.py | 指定区间均匀浮点数 | python uniform_for_floats.py |
| choice.py | 一维数组抽样 | python choice.py |
| choice_shuffle.py | choice的axis与shuffle参数 | python choice_shuffle.py |
| shuffle.py | 原地洗牌 | python shuffle.py |
| permutation_vs_shuffle.py | 副本排列 vs 原地打乱 | python permutation_vs_shuffle.py |
| permuted.py | 逐轴独立重排 | python permuted.py |
| decks.py | 扑克牌数据辅助函数 | python decks.py |
| high_deck_example.py | 高牌矩阵构造 | python high_deck_example.py |
| generator_swap_and_seeds.py | 位生成器与种子复现 | python generator_swap_and_seeds.py |
| array_constraints.py | 显式Generator与多维采样 | python array_constraints.py |
| cars_per_minute.py | 泊松 PMF 手算 | python cars_per_minute.py |
| poisson.py | 泊松随机采样 | python poisson.py |
| random_poisson_plot.py | 随机样本频数图 | python random_poisson_plot.py |
| sample_poisson_plot.py | 理论 PMF 曲线图 | python sample_poisson_plot.py |
建议按"入门 → 整数/浮点 → 抽样 → 洗牌/排列 → 种子与位生成器 → 泊松分布"的顺序依次运行,与教程正文对照理解。
小结
通过 numpy-rng 目录的配套代码,本文完整覆盖了 NumPy 新一代随机数生成的核心知识面:
- 入口统一:始终从
np.random.default_rng()创建Generator,获得与全局状态隔离、可复现的随机源; - 边界与形状:
integers()遵循[low, high)(endpoint=True可含上界),random()、uniform()、poisson()均支持size生成任意形状的样本数组; - 三种打乱语义:
shuffle()原地修改、permutation()返回副本、permuted()沿轴逐切片独立重排,三者在多维场景下行为差异明显,需按数据形态选择; - 种子与位生成器:相同种子产出完全一致的序列;
Generator与PCG64DXSM等位生成器可灵活组合,实现"换引擎不改采样代码"; - 分布验证闭环:以泊松分布为例,通过手算 PMF(
cars_per_minute.py)、随机采样(poisson.py)与双绘图脚本交叉验证,形成从理论到实证的完整方法论。
掌握这套GeneratorAPI,你便能在模拟、抽样、数据增强、蒙特卡洛实验等场景中写出既高效又可复现的随机逻辑。
- 示例工程
- 教程
【免费下载链接】materials
Bonus materials, exercises, and example projects for our Python tutorials
相关推荐
NumPy Philox 计数器型随机数生成器(Counter-based RNG)完全指南
NumPy Philox 计数器型随机数生成器(Counter based RNG)完全指南 导读 Philox 是 NumPy 中随 Generator 架构
科学计算数据分析NumPy 随机数生成(numpy.random)完全指南:default_rng、Generator、BitGenerator 与 SeedSequence 实战解析
NumPy 随机数生成(numpy.random)完全指南:default_rng、Generator、BitGenerator 与 SeedSequence
科学计算数据分析NumPy 生成正态分布随机数实战指南:default_rng、rng.normal 与分布可视化
NumPy 生成正态分布随机数实战指南:default_rng、rng.normal 与分布可视化 正态分布是统计建模、模拟仿真与机器学习中最常用的连续概率分布
示例工程教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考