【AI大模型--NumPy-06】随机数生成与蒙特卡洛模拟

06_randomMonteCarlo.py - 随机数生成与蒙特卡洛模拟

学习路径第 6 步 (共 10 步) | 难度:中级

概述

从随机数生成基础出发,逐步深入到蒙特卡洛方法的实际应用:圆周率估算、定积分计算、函数优化、排队模拟。

学习目标

  • 掌握 default_rng() 现代随机数 API (对比旧版 np.random
  • 了解常用概率分布:均匀分布、正态分布、二项分布、泊松分布等
  • 理解蒙特卡洛方法的核心思想(大数定律)
  • 能用蒙特卡洛方法解决实际问题

核心内容 (7 个模块)

模块 核心知识点
1. Generator 新旧接口对比 现代写法 vs 传统写法、种子复现
2. 常见概率分布 均匀分布、正态、二项、泊松、指数分布
3. 排列与选择 shuffle / permutation / 加权随机选取
4. 蒙特卡洛基本原理 大数定律、收敛过程可视化
5. 圆周率估算 经典投针法/飞镖法估算 pi 值
6. 积分与优化 蒙特卡洛积分计算、模拟退火优化
7. 排队模拟 M/M/1 排队模型的随机到达模拟

CODE

python 复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
=====================================
NumPy 随机数生成与蒙特卡洛模拟 (Random & Monte Carlo)
=====================================

本案例系统介绍 NumPy 随机数体系与蒙特卡洛方法:

1. Random Generator 新接口 (推荐)
2. 各种概率分布的采样
3. 随机排列、选择与洗牌
4. 蒙特卡洛核心思想
5. 实战案例: 圆周率估算 / 积分计算 / 模拟优化

【蒙特卡洛方法简介】
  通过大量随机抽样来近似求解数学问题。
  核心思想: 大数定律 --- 当试验次数趋近无穷时,
  事件频率收敛于其概率。

作者:bloxed
"""

import numpy as np


def separator(title):
    print(f"\n{'='*60}")
    print(f"  {title}")
    print('='*60)


# ============================================================
# 第一部分:随机数生成体系
# ============================================================
separator("一、随机数生成器 (新旧接口)")

print("""
【重要】NumPy 推荐使用新的 Generator API (v1.17+)

旧方式 (仍可用, 但不推荐新项目):
  np.random.seed(42)
  np.random.rand(5)

新方式 (推荐 ★★★):
  rng = np.random.default_rng(42)
  rng.random(5)

[新接口优势]
  - 统计性质更好 (PCG64 算法替代 MT19937)
  - 更快的速度
  - 支持并行独立流 (distributed computing)
""")

# 创建随机数生成器实例
rng = np.random.default_rng(seed=42)

print("\n--- 基础随机数 ---")
uniform_vals = rng.random(5)        # [0,1) 均匀分布
int_vals = rng.integers(0, 100, 8)  # [low, high) 整数
float_range = rng.uniform(10, 20, 6)

print(f"  uniform [0,1):     {np.round(uniform_vals, 3)}")
print(f"  integers [0,100):  {int_vals}")
print(f"  uniform [10,20]:   {np.round(float_range, 2)}")


# ============================================================
# 第二部分:常用概率分布
# ============================================================
separator("二、常用概率分布采样")

print("""
┌───────────────┬──────────────────┬─────────────────────────┐
│ 分布          │ 函数              │ 典型应用场景            │
├───────────────┼──────────────────┼─────────────────────────┤
│ 均匀分布       │ uniform()         │ 随机采样、初始化        │
│ 正态分布       │ normal()          │ 自然现象建模、噪声      │
│ 二项分布       │ binomial()        │ 成功/失败次数           │
│ 泊松分布       │ poisson()         │ 单位时间事件计数        │
│ 指数分布       │ exponential()     │ 等待时间模型            │
│ Beta 分布      │ beta()            │ 概率参数的不确定性      │
│ 多元正态       │ multivariate_normal() | 相关变量联合分布    │
└───────────────┴──────────────────┴─────────────────────────┘
""")

n = 10000

# 正态分布
normal_data = rng.normal(loc=100, scale=15, size=n)
print(f"正态分布 N(100,15), n={n}:")
print(f"  均值 ≈ {normal_data.mean():.1f} (理论值 100)")
print(f"  标准差 ≈ {normal_data.std():.1f} (理论值 15)")
print(f"  范围 [{normal_data.min():.1f}, {normal_data.max():.1f}]")

# 二项分布: 抛10次硬币, 正面朝上的次数 (重复10000次)
binom_data = rng.binomial(n=10, p=0.5, size=n)
print(f"\n二项分布 B(n=10,p=0.5), n={n}次实验:")
unique, counts = np.unique(binom_data, return_counts=True)
for u, c in zip(unique, counts):
    bar = '#' * int(c / n * 50)
    print(f"  k={u:<3} 频率={c/n*100:>5.1f}%  {bar}")

# 泊松分布: 每小时平均来3个顾客, 观察10000小时
poisson_data = rng.poisson(lam=3.0, size=n)
print(f"\n泊松分布 Pois(lambda=3):")
print(f"  均值 ≈ {poisson_data.mean():.2f} (理论值 3.0)")
print(f"  方差 ≈ {poisson_data.var():.2f} (泊松分布 均值≈方差)")

# 指数分布: 平均等待时间=2秒
exp_data = rng.exponential(scale=2.0, size=n)
print(f"\n指数分布 Exp(scale=2):")
print(f"  均值 ≈ {exp_data.mean():.2f} (理论值 2.0)")


# ============================================================
# 第三部分:随机排列与选择
# ============================================================
separator("三、随机操作: 排列/选择/无放回抽样")

students = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve',
            'Frank', 'Grace', 'Henry']

print(f"原始列表 ({len(students)} 人): {students}")

# 随机打乱 (返回副本, 不修改原数组)
shuffled = rng.permutation(students)
print(f"\n1. permutation (打乱): {shuffled}")

# 随机选取 (可重复)
chosen = rng.choice(students, size=3, replace=True)
print(f"2. choice 有放回选3人: {chosen}")
chosen_no_replace = rng.choice(students, size=3, replace=False)
print(f"3. choice 无放回选3人: {chosen_no_replace}")

# 加权随机选择 (概率不同)
weights = [0.3, 0.2, 0.1, 0.15, 0.05, 0.05, 0.1, 0.05]
weighted_chosen = rng.choice(students, size=10, p=np.array(weights)/sum(weights))
from collections import Counter
counts = Counter(weighted_chosen)
print(f"\n4. 加权选择 (Alice权重最高=30%):")
for name, cnt in counts.items():
    idx = students.index(name)
    print(f"   {name}: 出现{cnt}次 (原始权重={weights[idx]})")


# ============================================================
# 第四部分:蒙特卡洛案例一 ------ 估算圆周率 π
# ============================================================
separator("四、MC 案例 1: 估算圆周率 π")

print("""
【原理】在单位正方形 [0,1]x[0,1] 内随机投点:
  
  正方形面积 = 1 x 1 = 1
  四分之一圆面积 = π * r² / 4 = π/4 (r=1)
  
  若投了 N 个点, M 个落在圆内:
    M/N ≈ (π/4) / 1 = π/4
    所以 π ≈ 4M/N
  
  落入圆内的条件: x^2 + y^2 <= 1
""")

def estimate_pi(n_samples):
    """用蒙特卡洛法估算 π"""
    points = rng.uniform(0, 1, size=(n_samples, 2))
    distances_squared = points[:, 0]**2 + points[:, 1]**2
    inside_circle = distances_squared <= 1
    pi_estimate = 4 * inside_circle.sum() / n_samples
    return pi_estimate, inside_circle

# 不同样本量下的精度变化
sample_sizes = [100, 1000, 10000, 100000, 1000000]
print(f"{'样本量':>12} {'π 估算值':>12} {'误差':>12} {'圆内占比':>10}")
print("-" * 48)

pi_final, inside_final = None, None
for n in sample_sizes:
    pi_est, inside = estimate_pi(n)
    error = abs(pi_est - np.pi)
    ratio = inside.sum() / n
    print(f"{n:>12,} {pi_est:>12.6f} {error:>12.6f} {ratio:>9.4f}")
    pi_final, inside_final = pi_est, inside

print(f"\n真实 π 值: {np.pi:.6f}")
print(f"最佳估算:  {pi_final:.6f}")


# ============================================================
# 第五部分:蒙特卡洛案例二 ------ 数值积分
# ============================================================
separator("五、MC 案例 2: 数值定积分")

print("""
【任务】计算 ∫₀¹ sin(x) dx 的值

解析解: [-cos(x)]₀¹ = 1 - cos(1) ≈ 0.4597

【MC 方法】
  在 [0,1] 区间均匀取 N 个随机点 xi
  计算 f(xi) = sin(xi) 的平均值
  积分值 ≈ (b-a) × mean(f(x)) = 1 × mean(sin(x))
""")

n_integral = 500_000
x_samples = rng.uniform(0, 1, size=n_integral)
y_values = np.sin(x_samples)
integral_mc = y_values.mean() * (1 - 0)  # 区间长度=1

analytical = 1 - np.cos(1)
error = abs(integral_mc - analytical)

print(f"  样本量: {n_integral:,}")
print(f"  MC 结果:  {integral_mc:.6f}")
print(f"  解析解:   {analytical:.6f}")
print(f"  绝对误差: {error:.6f}")
print(f"  相对误差: {error/analytical*100:.3f}%")

# 可视化展示 (文字版直方图)
print(f"\n  函数值分布:")
hist, edges = np.histogram(y_values, bins=20)
max_h = max(hist)
for i in range(len(hist)):
    lo, hi = edges[i], edges[i+1]
    bar_len = int(hist[i] / max_h * 40)
    print(f"    [{lo:.3f}, {hi:.3f}): {'#' * bar_len} ({hist[i]})")


# ============================================================
# 第六部分:蒙特卡洛案例三 ------ 优化问题
# ============================================================
separator("六、MC 案例 3: 随机搜索优化 (Rastrigin函数)")

print("""
【任务】寻找 Rastrigin 函数的全局最小值 (已知在原点处为0)

  f(x,y) = A*n + Σ[xi² - A*cos(2πxi)]
  其中 A=10, n=2 (二维)
  
  这是一个多峰优化问题,有很多局部极小值,
  梯度下降容易陷入局部最优。
  MC随机搜索可以较好地探索全局!
""")

def rastrigin(x, y, A=10):
    """Rastrigin 测试函数"""
    return A * 2 + (x**2 - A * np.cos(2*np.pi*x)) + (y**2 - A * np.cos(2*np.pi*y))

# 随机搜索
n_search = 200_000
search_x = rng.uniform(-5.12, 5.12, size=n_search)
search_y = rng.uniform(-5.12, 5.12, size=n_search)
z_values = rastrigin(search_x, search_y)

best_idx = np.argmin(z_values)
best_x, best_y = search_x[best_idx], search_y[best_y]
best_z = z_values[best_idx]

print(f"  搜索空间: [-5.12, 5.12] x 2维")
print(f"  随机采样点: {n_search:,}")
print(f"\n  找到的最优解:")
print(f"    x = {best_x:.6f}")
print(f"    y = {best_y:.6f}")
print(f"    f(x,y) = {best_z:.6f}")
print(f"  全局最优: f(0,0) = 0")
print(f"  误差: {abs(best_z):.6f}")

# 分析搜索质量
thresholds = [0.01, 0.1, 1.0, 5.0]
print(f"\n  解的质量分布:")
for thresh in thresholds:
    count = np.sum(z_values < thresh)
    pct = count / n_search * 100
    print(f"    f(x,y) < {thresh:<5} : {count:>6,} 点 ({pct:>5.2f}%)")


# ============================================================
# 第七部分:蒙特卡洛案例四 ------ 模拟排队系统
# ============================================================
separator("七、MC 案例 4: 模拟排队系统 (离散事件模拟)")

print("""
【场景】单服务台排队系统 (M/M/1队列简化版)

  参数:
    - 到达间隔: 服从指数分布 (平均2分钟一个顾客)
    - 服务时间: 服从指数分布 (平均1.5分钟服务一个顾客)
  
  目标: 估计平均等待时间和队列长度
""")

n_customers = 5000
arrival_intervals = rng.exponential(scale=2.0, size=n_customers)  # 到达间隔
service_times = rng.exponential(scale=1.5, size=n_customers)       # 服务时间

# 模拟过程
arrival_times = np.cumsum(arrival_intervals)  # 每个顾客到达时刻
departure_times = np.zeros(n_customers)       # 每个顾客离开时刻
wait_times = np.zeros(n_customers)             # 等待时间

for i in range(n_customers):
    if i == 0:
        departure_times[i] = arrival_times[i] + service_times[i]
        wait_times[i] = 0
    else:
        # 如果前一个人还没走完,需要等待
        start_service = max(arrival_times[i], departure_times[i-1])
        wait_times[i] = max(0, start_service - arrival_times[i])
        departure_times[i] = start_service + service_times[i]

print(f"  模拟顾客总数: {n_customers:,}")
print(f"  总运行时间:   {arrival_times[-1]:.1f} 分钟")
print(f"\n  --- 统计结果 ---")
print(f"  平均等待时间:  {wait_times.mean():.2f} 分钟")
print(f"  最大等待时间:  {wait_times.max():.2f} 分钟")
print(f"  无需等待比例:  {(wait_times == 0).mean()*100:.1f}%")
print(f"  等待 > 5分钟比例: {(wait_times > 5).mean()*100:.1f}%")
print(f"  系统利用率:     {service_times.mean()/arrival_intervals.mean()*100:.1f}%")


# ============================================================
# 总结
# ============================================================
separator("总结: 随机数 & 蒙特卡洛速查")

summary = r"""
+------------------------------------------------------------+
|  NumPy Random & Monte Carlo                                 |
+------------------------------------------------------------+
|                                                            |
|  [创建Generator]                                            |
|  rng = np.random.default_rng(seed)                         |
|                                                            |
|  [基础随机]                                                 |
|  rng.random(size)      → [0,1) 均匀浮点                    |
|  rng.integers(lo,hi)   → [lo,hi) 均匀整数                  |
|  rng.uniform(a,b)      → [a,b) 均匀浮点                    |
|                                                            |
|  [概率分布]                                                 |
|  rng.normal(mu,sigma)  → 正态分布                          |
|  rng.binomial(n,p)     → 二项分布                          |
|  rng.poisson(lam)      → 泊松分布                          |
|  rng.exponential(scale)→ 指数分布                          |
|                                                            |
|  [随机操作]                                                 |
|  rng.choice(pop,size)   → 随机选取                         |
|  rng.shuffle(arr)        → 原地打乱                         |
|  rng.permutation(arr)   → 返回打乱副本                      |
|                                                            |
|  [Monte Carlo 三步曲]                                      |
|  1. 在定义域内大量随机采样                                  |
|  2. 计算每个样本的目标函数值                                |
|  3. 用统计均值近似期望/积分/概率                            |
|                                                            |
|  收敛速度: O(1/sqrt(N)), 要精度提高10倍需100倍采样量       |
+------------------------------------------------------------+
"""
print(summary)

print("\n运行完毕!")
相关推荐
szxinmai主板定制专家2 小时前
基于ZYNQ MPSOC图像采集与压缩系统总体设计方案
linux·arm开发·人工智能·嵌入式硬件·fpga开发
GOTXX2 小时前
SenseNova U1 实战体验:API 调用 + OpenClaw 接入全流程
服务器·网络·人工智能·语言模型
生成论实验室2 小时前
用事件关系网络重新理解AI(三):激活函数、微调与元学习
人工智能·学习·算法·语言模型·可信计算技术
@蔓蔓喜欢你2 小时前
Jest 测试框架:构建可靠的测试体系
人工智能·ai
Narv工程师2 小时前
嵌入式机器人控制器算力评估:从DMIPS到WCET的完整指南
人工智能·算法·机器学习
searchforAI2 小时前
AI多模态技术:从语音识别到AI结构化笔记是怎么实现的
人工智能·经验分享·笔记·gpt·whisper·语音识别
LCG元2 小时前
RAG - 大模型检索增强生成深度解析:本地知识库 / 企业级落地优化配置
人工智能·算法
用户5191495848452 小时前
WordPress ACF City Selector 插件任意文件上传漏洞利用工具 (CVE-2024-56264)
人工智能·aigc
AI袋鼠帝2 小时前
挖到个巨省Token的开源Agent,还能以复利的方式变现(企业、开发者必看)!
人工智能