Numpy第九章 随机抽样

Numpy第九章 随机抽样 一.随机抽样基础numpy.randomnumpy.random简介是对 Python 内置random模块的扩展。支持高效生成多种概率分布的随机样本如正态、泊松、二项等。Seed随机种子np.random.seed(seedNone)作用控制随机数生成器的初始状态。相同 seed → 相同随机序列可复现结果。不设 seed → 基于系统时间自动设置每次不同。建议在数据预处理、实验中固定 seed 以保证可重复性。二.离散型随机变量1.二项分布二项分布用于描述n 次独立重复伯努利试验中成功次数的概率分布满足每次试验仅两种结果成功 / 失败各试验相互独立单次成功概率为 p失败概率为 1−p典型场景猜拳赢的次数、石油勘探出油数、投硬币正面次数等。1概率质量函数PMF数学形式代码形式scipy.stats.binom.pmfbinom.pmf(k, n, p) choose(n, k) * p**k * (1-p)**(n-k)含义计算 n 次试验中恰好成功 k 次的概率。2期望与方差期望E(X)np方差Var(X)np(1−p)代码计算scipy.stats.binom.statsfrom scipy import stats mean, var stats.binom.stats(n, p, momentsmv) # m期望v方差3例题分析采样模拟numpy.random.binomial/binom.rvsimport numpy as np from scipy import stats import matplotlib.pyplot as plt np.random.seed(20200605) # 固定随机种子保证可复现 n 9 # 试验次数 p 0.1 # 单次成功概率 size 50000 # 采样次数 # 方式1numpy采样 x np.random.binomial(n, p, size) # 方式2scipy采样 y stats.binom.rvs(n, p, sizesize)概率计算与结果统计以「9 口勘探井全失败」为例# 统计成功次数为0的概率 print(np.sum(x 0) / size) # 输出约0.3897接近理论值0.387 # 计算理论PMF s stats.binom.pmf(range(10), n, p) print(np.around(s, 3)) # 输出[0.387, 0.387, 0.172, 0.045, 0.007, 0.001, 0., 0., 0., 0.]以「投 2 次硬币2 次均为正面」为例n 2 p 0.5 x np.random.binomial(n, p, size) # 统计各成功次数概率 print(np.sum(x 0) / size) # 约0.25154理论值0.25 print(np.sum(x 1) / size) # 约0.49874理论值0.5 print(np.sum(x 2) / size) # 约0.24972理论值0.25 # 理论PMF验证 s stats.binom.pmf(range(n1), n, p) print(np.around(s, 3)) # 输出[0.25, 0.5, 0.25]可视化分布plt.hist(x, densityTrue) # densityTrue归一化显示概率密度 plt.xlabel(随机变量成功次数) plt.ylabel(样本中出现的频率) plt.show()可视化可直观展示二项分布的离散形态验证模拟结果与理论分布一致。2.泊松分布泊松分布用于描述单位时间 / 单位空间内随机独立事件发生次数的概率分布满足事件发生的平均速率恒定记为 λ各事件发生相互独立事件发生次数无上限典型场景单位时间内电话呼叫数、路口车流量、机器故障次数、订单到达数等。1概率质量函数PMF数学形式代码形式scipy.stats.poisson.pmfpoisson.pmf(k, lam) exp(-lam) * lam**k / factorial(k)含义计算单位时间 / 空间内事件恰好发生 k 次的概率。2期望与方差泊松分布的期望和方差完全相等都等于 λ期望E(X)λ方差Var(X)λ代码计算scipy.stats.poisson.statsfrom scipy import stats mean, var stats.poisson.stats(lam, momentsmv)3例题分析题目某航空公司平均每小时接到42 次订票电话。求10 分钟内恰好接到 6 次电话的概率。步骤 1计算参数 λ10 分钟 1/6 小时 λ42÷67步骤 2采样模拟numpy.random.poissonimport numpy as np from scipy import stats import matplotlib.pyplot as plt # 解决中文显示警告 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False np.random.seed(20200605) lam 7 # 10分钟平均电话数 size 50000 # 采样次数 # 方式1numpy 采样 sample_np np.random.poisson(lam, size) # 方式2scipy 采样 sample_scipy stats.poisson.rvs(lam, sizesize)步骤 3概率计算与结果统计求10 分钟恰好 6 次电话的概率# 模拟统计概率 sim_prob np.sum(sample_np 6) / size print(f模拟概率{sim_prob:.6f}) # 理论PMF计算 theory_prob stats.poisson.pmf(6, lam) print(f理论概率{theory_prob:.15f}) # 输出结果 # 模拟概率0.149880 # 理论概率0.149002779674338步骤 4期望与方差mean_theory, var_theory stats.poisson.stats(lam, momentsmv) print(f期望 E(X) {mean_theory:.4f}) print(f方差 Var(X) {var_theory:.4f}) # 输出 # 期望 E(X) 7.0000 方差 Var(X) 7.0000步骤 5可视化分布plt.figure(figsize(10,5)) k_list np.arange(0, 20) plt.hist(sample_np, binsk_list, densityTrue, alpha0.6, colorskyblue) plt.plot(k_list, stats.poisson.pmf(k_list, lam), ro-, linewidth2) plt.title(f泊松分布 P(λ{lam})) plt.xlabel(电话次数 k) plt.ylabel(概率) plt.grid(alpha0.3) plt.show()3.超几何分布超几何分布描述的是无放回抽样的概率分布。其特点如下各次实验不是独立的因为不放回每次抽选会改变总体构成。各次实验成功的概率也不相等随着抽取进行成功元素比例变化。1numpy.random.hypergeometric函数函数numpy.random.hypergeometric(ngood, nbad, nsample, sizeNone)参数含义ngood总体中具有“成功”标志的元素个数例如狗的数量。nbad总体中不具有“成功”标志的元素个数例如非狗的数量。nsample抽取元素的次数样本容量。size采样的次数生成多少个样本。返回值​ 抽取nsample个元素中具有“成功”标识的元素个数。例一共20只动物7只是狗13只是非狗。从中抽取12只求抽到3只狗的概率无放回。import numpy as np np.random.seed(20200605) size 500000 x np.random.hypergeometric(ngood7, nbad13, nsample12, sizesize) prob np.sum(x 3) / size # 计算抽到3只狗的频率 print(prob) # 输出约为 0.1986642使用scipy.stats.hypergeom函数进行精确概率计算函数hypergeom.pmf(k, M, n, N)用于计算在给定参数下恰好抽到k个成功元素的概率。参数含义M总体容量M ngood nbad。n总体中成功元素的个数即ngood。N抽取的样本容量即nsample。k我们关心的成功元素个数。例from scipy import stats x range(8) s stats.hypergeom.pmf(x, M20, n7, N12) # 计算抽到0~7只狗的概率 print(np.round(s, 3)) # 输出[0. 0.004 0.048 0.199 0.358 0.286 0.095 0.01 ]可见抽到3只狗的概率约为0.199与上面的模拟结果一致。3超几何分布的均值与方差公式注释当总体容量 M很大时M−N/M−1​≈1此时超几何分布近似于二项分布 B(N,p)其中 pn/M。Python 计算均值与方差stats.hypergeom.stats(M20, n7, N12, momentsmv)该函数会返回一个元组(均值, 方差)。三.连续型随机变量1.均匀分布1均匀分布定义在区间[low, high)内所有值被抽到的概率相等半开区间包含low不包含high。用途模拟公平随机选择、随机抽样、初始化权重等。2numpy.random.uniform函数numpy.random.uniform(low0.0, high1.0, sizeNone)功能从均匀分布中抽取随机数。参数low最小值包含。high最大值不包含。size输出数组的形状如size5表示生成5个数size(2,3)表示生成2行3列的数组。例import numpy as np np.random.seed(20200614) # 设置随机种子保证结果可复现 # 生成单个 [0, 100) 之间的随机数 print(np.random.uniform()) # 输出0.7594819171852776 # 生成5个 [0, 100) 之间的随机数 print(np.random.uniform(size5)) # 输出[0.75165827 0.16552651 0.0538581 0.46671446 0.89076925] # 生成 4行3列 的 [0, 100) 随机数矩阵 print(np.random.uniform(size(4, 3))) # 输出 # [[0.10073292 0.14624784 0.40273923] # [0.21844459 0.2226682 0.37246217] # [0.50334257 0.01714939 0.47780388] # [0.08755349 0.86500477 0.70566398]]3numpy.random.rand()函数numpy.random.rand(d0, d1, ..., dn)功能生成[0, 1)之间均匀分布的随机数。参数d0, d1, ..., dn是输出数组的各维度大小。特点是uniform(low0.0, high1.0)的特例无需指定low和high。例np.random.seed(20200614) # 生成单个 [0, 1) 随机数 print(np.random.rand()) # 输出0.7594819171852776 # 生成5个 [0, 1) 随机数 print(np.random.rand(5)) # 输出[0.75165827 0.16552651 0.0538581 0.46671446 0.89076925] # 生成 4行3列 的 [0, 1) 随机数矩阵 print(np.random.rand(4, 3)) # 输出同上4numpy.random.randint()函数numpy.random.randint(low, highNone, sizeNone, dtypel)功能生成指定范围内的随机整数。参数low最小值包含。high最大值不包含。如果为None则范围是[0, low)。size输出数组形状。dtype数据类型默认为整数。例np.random.seed(20200614) # highNone生成 [0, 2) 之间的随机整数即 0 或 1 x np.random.randint(2, size10) print(x) # 输出[0 0 0 1 0 1 0 0 0 0] # high1生成 [0, 1) 之间的整数 → 只能是 0 x np.random.randint(1, size10) print(x) # 输出[0 0 0 0 0 0 0 0 0 0] # 生成 3行4列 的 [1, 10) 之间随机整数即 1~9 x np.random.randint(1, 10, size(3, 4)) print(x) # 输出 # [[2 1 7 7] # [7 2 4 6] # [8 7 2 8]]均匀分布的概率验证用经验频率验证均匀分布的性质验证区间概率在[0, 100)区间内随机数落在[10, 50)的概率应为(50-10)/100 0.4。a 0 b 100 size 50000 x np.random.uniform(a, b, sizesize) # 计算落在 [10, 50) 的频率 y (np.sum(x 50) - np.sum(x 10)) / size print(y) # 输出0.40144接近理论值 0.4使用scipy.stats.uniform.cdf计算理论概率from scipy import stats a stats.uniform.cdf(10, 0, 100) # P(X 10) b stats.uniform.cdf(50, 0, 100) # P(X 50) print(b - a) # 输出0.4精确值可视化使用matplotlib.pyplot.hist()绘制直方图直观展示均匀分布的特征import matplotlib.pyplot as plt plt.hist(x, bins20) # 绘制直方图分20个区间 plt.show()直方图应呈现“近似矩形”说明各区间概率大致相等。对比函数区间输出类型特点numpy.random.uniform[low, high)浮点数最通用可自定义区间numpy.random.rand[0, 1)浮点数uniform的特例更简洁numpy.random.randint[low, high)整数专为整数设计常用于离散抽样2.正态分布1标准正态分布标准正态分布是指均值为 0标准差为 1 的正态分布。a使用numpy.random.randn函数生成标准正态分布随机数函数numpy.random.randn(d0, d1, ..., dn)功能返回一个或多个服从标准正态分布的随机数。参数d0, d1, ..., dn是数组的维度如果省略则返回单个随机数。例import numpy as np import matplotlib.pyplot as plt from scipy import stats np.random.seed(20200614) # 设置随机种子保证结果可复现 size 50000 x np.random.randn(size) # 生成 50000 个标准正态分布的随机数 # 计算落在不同区间内的概率经验概率 y1 (np.sum(x 1) - np.sum(x -1)) / size # P(-1 X 1) y2 (np.sum(x 2) - np.sum(x -2)) / size # P(-2 X 2) y3 (np.sum(x 3) - np.sum(x -3)) / size # P(-3 X 3) print(y1) # 输出约为 0.68596 (理论值约为 0.6827) print(y2) # 输出约为 0.95456 (理论值约为 0.9545) print(y3) # 输出约为 0.99744 (理论值约为 0.9973) # 绘制直方图 plt.hist(x, bins20) plt.show()b 使用scipy.stats.norm.cdf函数计算理论概率函数签名stats.norm.cdf(x, loc0, scale1)功能计算标准正态分布的累积分布函数 (CDF) 值。参数x要计算 CDF 的点。loc均值默认 0。scale标准差默认 1。例y1 stats.norm.cdf(1) - stats.norm.cdf(-1) y2 stats.norm.cdf(2) - stats.norm.cdf(-2) y3 stats.norm.cdf(3) - stats.norm.cdf(-3) print(y1) # 输出约为 0.6826894921370859 (理论值) print(y2) # 输出约为 0.9544997361036416 (理论值) print(y3) # 输出约为 0.9973002039367398 (理论值)2一般正态分布一般正态分布可以通过改变均值mu和标准差sigma来实现。a使用numpy.random.normal函数生成一般正态分布随机数函数签名numpy.random.normal(loc0.0, scale1.0, sizeNone)功能返回指定均值和标准差的正态分布随机数。参数loc均值。scale标准差。size输出数组的形状。例np.random.seed(20200614) # 生成均值为 5标准差为 0.5 的正态分布随机数 x 0.5 * np.random.randn(2, 4) 5 print(x) # 输出 # [[5.39654234 5.4088702 5.49104652 4.95817289] # [4.31977933 4.76502391 4.70720327 4.36239023]] # 或者使用 stats.norm.rvs x 0.5 * stats.norm.rvs(size(2,4)) 5 print(x) # 输出 # [[5.39654234 5.4088702 5.49104652 4.95817289] # [4.31977933 4.76502391 4.70720327 4.36239023]]b指定均值和标准差生成随机数例np.random.seed(20200614) mu 5 # 均值 sigma 0.5 # 标准差 size 50000 x np.random.normal(mu, sigma, size) print(np.mean(x)) # 输出约为 4.9964 (接近 mu5) print(np.std(x, ddof1)) # 输出约为 0.4987 (接近 sigma0.5) # 绘制直方图 plt.hist(x, bins20) plt.show()3核心公式与概念标准正态分布均值mu 0标准差sigma 1。一般正态分布均值mu标准差sigma。标准化任何正态分布都可以通过Z (X - mu) / sigma转换为标准正态分布。经验法则约 68% 的数据落在mu ± sigma之间。约 95% 的数据落在mu ± 2*sigma之间。约 99.7% 的数据落在mu ± 3*sigma之间。4总结numpy.random.randn用于生成标准正态分布随机数。numpy.random.normal用于生成指定均值和标准差的正态分布随机数。scipy.stats.norm.cdf用于计算正态分布的累积概率。scipy.stats.norm.rvs用于生成指定参数的正态分布随机数。3.指数分布1指数分布定义指数分布通常用于描述事件发生的时间间隔例如顾客到达商店的时间间隔、设备发生故障的时间间隔等。数学表示概率密度函数 (PDF)f(x; λ) λ * e^(-λx)其中x ≥ 0λ 0是速率参数。累积分布函数 (CDF)F(x; λ) 1 - e^(-λx)。参数说明scale在numpy.random.exponential中scale 1/λ表示均值期望值。loc位置参数默认为 0表示分布从 0 开始。2使用numpy.random.exponential函数生成随机数函数numpy.random.exponential(scale1.0, sizeNone)功能从指数分布中抽取随机数。参数scale尺度参数即1/λ均值。size输出数组的形状。例import numpy as np import matplotlib.pyplot as plt from scipy import stats np.random.seed(20200614) # 设置随机种子保证结果可复现 lam 7 # 速率参数 λ scale 1 / lam # 尺度参数 scale 1/λ size 50000 # 样本数量 # 生成指数分布随机数 x np.random.exponential(scale, size) # 计算落在不同区间内的经验概率 y1 (np.sum(x 1 / 7)) / size # P(X 1/λ) y2 (np.sum(x 2 / 7)) / size # P(X 2/λ) y3 (np.sum(x 3 / 7)) / size # P(X 3/λ) print(y1) # 输出约为 0.63218 (理论值约为 0.6321) print(y2) # 输出约为 0.86518 (理论值约为 0.8647) print(y3) # 输出约为 0.95056 (理论值约为 0.9502) # 绘制直方图 plt.hist(x, bins20) plt.show()3 使用scipy.stats.expon函数计算理论概率函数stats.expon.cdf(x, loc0, scale1)功能计算指数分布的累积分布函数值即P(X ≤ x)。例# 计算理论概率 y1_theory stats.expon.cdf(1 / 7, scale1 / lam) y2_theory stats.expon.cdf(2 / 7, scale1 / lam) y3_theory stats.expon.cdf(3 / 7, scale1 / lam) print(y1_theory) # 输出约为 0.6321205588285577 print(y2_theory) # 输出约为 0.8646647167633873 print(y3_theory) # 输出约为 0.9502129316321364总结经验概率 vs 理论概率通过numpy.random.exponential生成的随机数计算的经验概率与通过scipy.stats.expon.cdf计算的理论概率非常接近验证了实现的准确性。指数分布的特性均值E(X) 1/λ方差Var(X) 1/λ²无记忆性P(X s t | X s) P(X t)四.其它随机函数1.随机从序列中获取元素numpy.random.choice函数功能从一个 1-D 数组或整数a中随机生成样本。函数numpy.random.choice(a, sizeNone, replaceTrue, pNone)参数说明a如果是整数则从np.arange(a)即0到a-1的整数序列中抽样如果是数组则直接从数组元素中抽样。size输出数组的形状例如size3表示生成 3 个元素size(2,4)表示生成 2 行 4 列的数组。replace是否有放回抽样True表示放回元素可重复False表示不放回元素不重复。p每个元素被抽取的概率权重长度需与a一致且所有p之和为 1。例从整数序列中抽样默认有放回等概率import numpy as np np.random.seed(20200614) # 设置随机种子保证结果可复现 x np.random.choice(10, 3) # 从 0-9 中随机选 3 个有放回等概率 print(x) # 输出[2 0 1]每次运行可能不同但种子固定后结果一致带权重的抽样指定概率px np.random.choice(10, 3, p[0.05, 0, 0.05, 0.9, 0, 0, 0, 0, 0, 0]) # p[3]0.9 表示第 4 个元素索引 3被抽到的概率为 90% print(x) # 输出[3 2 3]因 p[3] 很大大概率抽到 3无放回抽样replaceFalsex np.random.choice(10, 3, replaceFalse, p[0.05, 0, 0.05, 0.9, 0, 0, 0, 0, 0, 0]) # 无放回因此 3 最多出现一次即使 p[3] 很大 print(x) # 输出[3 0 2]元素不重复从字符串列表中抽样aa_milne_arr [pooh, rabbit, piglet, Christopher] x np.random.choice(aa_milne_arr, 5, p[0.5, 0.1, 0.1, 0.3]) # 从列表中选 5 个有放回权重pooh(0.5), rabbit(0.1), piglet(0.1), Christopher(0.3) print(x) # 输出[pooh rabbit pooh pooh pooh]pooh 概率最高结合np.random.randint的抽样间接生成序列x np.random.randint(0, 10, 3) # 等价于 np.random.choice(10, 3)从 0-9 选 3 个 print(x)2.对数据集进行洗牌操作1洗牌Shuffling函数numpy.random.shuffle(x)直接修改原数组x原地操作返回None。如果x是多维数组仅沿第 0 轴行方向打乱顺序子数组内部元素顺序不变。例shuffle的基本用法原地打乱一维数组import numpy as np np.random.seed(20200614) # 设置随机种子保证结果可复现 x np.arange(10) # 生成数组 [0, 1, 2, ..., 9] np.random.shuffle(x) # 原地打乱 x 的顺序 print(x) # 输出[6 8 7 5 3 9 1 4 0 2]每次运行可能不同但种子固定后结果一致例shuffle处理多维数组仅沿第 0 轴打乱x np.arange(20).reshape((5, 4)) # 生成 5 行 4 列的数组 # 原始 x # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11] # [12 13 14 15] # [16 17 18 19]] np.random.shuffle(x) # 沿第 0 轴行打乱 print(x) # 输出示例 # [[ 4 5 6 7] # [ 0 1 2 3] # [12 13 14 15] # [ 8 9 10 11] # [16 17 18 19]] # 注意每一行的元素顺序不变仅行的顺序被打乱。2排列Permutation函数numpy.random.permutation(x)不修改原数组返回一个新的打乱后的数组或打乱后的序列。如果x是整数返回一个打乱的np.arange(x)如果x是数组返回数组的打乱版本与shuffle类似沿第 0 轴打乱。例permutation的基本用法返回打乱后的新数组np.random.seed(20200614) x [1, 4, 9, 12, 15] # 列表 y np.random.permutation(x) # 返回打乱后的新列表原 x 不变 print(np.random.permutation([1, 4, 9, 12, 15])) # 输出[4 1 9 15 12]示例 print(x) # 原列表 x 不变[1, 4, 9, 12, 15]例permutation处理多维数组沿第 0 轴打乱返回新数组x np.arange(20).reshape((5, 4)) # 生成 5 行 4 列的数组 y np.random.permutation(x) # 返回打乱后的新数组原 x 不变 print(y) # 输出示例 # [[ 8 9 10 11] # [ 0 1 2 3] # [12 13 14 15] # [ 4 5 6 7] # [16 17 18 19]] print(x) # 原数组 x 不变仍为原来的顺序3总结shuffle原地打乱直接修改原数组仅沿第 0 轴打乱多维数组。permutation返回打乱后的新数组不修改原数组沿第 0 轴打乱多维数组。两者在打乱一维数组时效果类似但shuffle无返回值修改原数组permutation返回新数组保留原数组。