3、概率分布采样:均匀分布、正态分布、对数正态分布,以及如何用Python生成它们

做蒙特卡洛模拟,说白了就是在跟随机数打交道。

你想想看,我们要模拟市场未来一万种可能的走势,总不能靠拍脑袋吧?得有个靠谱的数学工具来生成这些随机样本。这就是我今天要聊的——概率分布采样。

我个人习惯把概率分布理解成「随机数的模具」。不同的模具,压出来的随机数形状不一样。有的均匀散开,有的中间多两头少,有的永远不碰负数。咱们做压力测试,选对模具比啥都重要。

核心观点:蒙特卡洛模拟的精度,90%取决于你选的分布对不对。分布选错了,跑再多路径也是白搭。

3.1 均匀分布:最基础的随机数

均匀分布,说白了就是「众生平等」。在某个区间内,每个数值出现的概率一模一样。

比如你掷骰子,1到6点,每个面概率都是1/6。这就是离散版的均匀分布。连续版的呢?比如在0到1之间随便取一个数,每个小数出现的概率都一样。

Python里怎么生成?

我最早学Python时,用的就是 random.uniform。后来做量化了,基本只用NumPy,因为快。

import numpy as np

# 生成10000个[0,1)之间的均匀分布随机数
samples = np.random.uniform(0, 1, 10000)

# 生成[-1, 1]之间的均匀分布
samples2 = np.random.uniform(-1, 1, 5000)

# 查看前5个样本
print(samples[:5])
# 输出类似:[0.3745, 0.9501, 0.7320, 0.5987, 0.1560]

我在项目中遇到过一个坑:均匀分布虽然简单,但用它模拟资产价格走势,基本是错的。因为真实市场里,极端涨跌的概率比均匀分布预测的要高得多。所以均匀分布一般只用来生成初始参数,或者做最简单的敏感性分析。

小技巧:如果你需要整数均匀分布,用 np.random.randint(low, high, size)。比如模拟掷骰子:np.random.randint(1, 7, 100)

3.2 正态分布:金融建模的基石

正态分布,也叫高斯分布。它的形状像个钟,中间高两边低。你想想看,人的身高、考试成绩、测量误差,基本都是正态分布。

在金融里,正态分布的地位曾经不可动摇。Black-Scholes期权定价模型,假设的就是资产收益率服从正态分布。

两个关键参数:

  • 均值(μ):决定钟的中心位置。比如年化收益率5%,均值就是0.05。
  • 标准差(σ):决定钟的胖瘦。标准差越大,数据越分散,风险越高。

Python生成正态分布样本:

import numpy as np

# 生成标准正态分布(均值0,标准差1)
standard_normal = np.random.normal(0, 1, 10000)

# 生成自定义正态分布(均值0.05,标准差0.2)
custom_normal = np.random.normal(0.05, 0.2, 10000)

# 查看统计量
print(f"均值: {np.mean(custom_normal):.4f}")
print(f"标准差: {np.std(custom_normal):.4f}")
# 输出类似:均值: 0.0498,标准差: 0.2003

我曾经犯过一个低级错误:直接用正态分布模拟股票价格,结果跑出来一堆负数。股票价格怎么可能为负?后来才意识到,正态分布是对数收益率(log return)的假设,不是价格本身的假设。这个坑,很多新手都会踩。

注意:正态分布允许负值,且尾部较薄。这意味着它低估了极端事件(比如金融危机)的发生概率。2008年之后,很多量化团队开始用「肥尾分布」替代正态分布。

3.3 对数正态分布:资产价格的天然模型

对数正态分布,名字听着唬人,其实逻辑很简单:如果一个变量的对数服从正态分布,那这个变量本身就服从对数正态分布。

为什么它适合模拟资产价格?

  • 价格永远大于0(对数正态分布只取正值)
  • 价格涨跌不对称(跌到0有下限,涨可以无限)
  • 符合实际市场的偏态特征

Python生成对数正态分布:

import numpy as np

# 方法1:先取对数,再指数化
mu, sigma = 0.05, 0.2  # 对数收益率参数
log_returns = np.random.normal(mu, sigma, 10000)
prices = np.exp(log_returns)  # 假设初始价格为1

# 方法2:直接用lognormal函数
# 注意:np.random.lognormal的mean和sigma是对数空间的参数
prices_direct = np.random.lognormal(mu, sigma, 10000)

# 查看价格范围
print(f"价格最小值: {np.min(prices):.4f}")
print(f"价格最大值: {np.max(prices):.4f}")
print(f"价格中位数: {np.median(prices):.4f}")
# 输出类似:最小值: 0.6183,最大值: 2.1457,中位数: 1.0512

我个人习惯用方法1,因为逻辑更清晰。先模拟对数收益率(正态分布),再累乘得到价格路径。这样每一步都能检查中间结果,调试起来方便。

实战经验:做压力测试时,我通常用对数正态分布模拟资产价格,用正态分布模拟收益率。记住这个对应关系:价格→对数正态,收益率→正态。搞反了,模型就废了。

3.4 三种分布的对比与选择

为了让你看得更清楚,我整理了一张对比表:

特性 均匀分布 正态分布 对数正态分布
取值范围 [a, b] 区间内 (-∞, +∞) (0, +∞)
形状 平顶 钟形对称 右偏(长尾在右边)
适用场景 参数采样、敏感性分析 收益率、误差项 资产价格、交易量
极端事件概率 较低 较高(右尾)
Python生成函数 np.random.uniform np.random.normal np.random.lognormal

嗯,这里要注意:没有哪个分布是万能的。我见过有人硬要用正态分布模拟期权价格,结果Delta对冲怎么都对不上。后来换成对数正态,问题迎刃而解。

3.5 知识体系总览

下面这张图,是我自己梳理的三种分布的核心逻辑。你看一眼,就能明白它们之间的关系:

概率分布采样知识体系 概率分布采样 均匀分布 正态分布 对数正态分布 取值范围:[a, b] 形状:平顶 适用:参数采样 函数:uniform() 取值范围:(-∞, +∞) 形状:钟形对称 适用:收益率 函数:normal() 取值范围:(0, +∞) 形状:右偏 适用:资产价格 函数:lognormal() 核心原则:选对分布,模拟就成功了一半

你看这张图,从左到右,分布的复杂度在增加。均匀分布最简单,对数正态分布最贴近真实市场。做压力测试时,我一般先用均匀分布做快速扫描,再用对数正态分布做精细模拟。

一个实用建议:刚开始做蒙特卡洛模拟,别追求花哨的分布。先把均匀、正态、对数正态这三种吃透。我见过太多人一上来就用t分布、柯西分布,结果连参数怎么设都搞不清楚。基础打牢了,后面自然水到渠成。

好了,关于概率分布采样,今天就聊到这儿。这三种分布,你可以在代码里多跑几遍,看看生成的随机数长什么样。亲手试试,比看十遍文章都管用。


公众号:蓝海资料掘金营,微信deep3321