如何在Python中实现自定义标准差区间占比的正态分布采样
自定义分位正态分布采样Python实现
你要求的标准差区间占比和标准正态分布固有分位特性不符,因此采用逆变换采样方案实现,具体内容如下:
实现思路
- 先根据要求的区间占比定义离散分位点映射:
- ±1σ区间占比50% → 累积概率0.25对应-1σ,0.75对应1σ
- ±2σ区间占比82% → 累积概率0.09对应-2σ,0.91对应2σ
- ±3σ区间占比96% → 累积概率0.02对应-3σ,0.98对应3σ
- 对离散分位点做线性插值,得到连续的分位到样本值的映射关系
- 均匀采样[0,1]区间的随机值,通过映射关系转换得到符合要求的样本
完整代码实现
import numpy as np from scipy.interpolate import interp1d # 预定义分位点和对应的标准差倍数 quantiles = np.array([0.02, 0.09, 0.25, 0.5, 0.75, 0.91, 0.98]) std_multiples = np.array([-3, -2, -1, 0, 1, 2, 3]) # 构建插值函数,extrapolate用于处理3σ以外的采样值 quantile_to_std = interp1d(quantiles, std_multiples, kind='linear', fill_value="extrapolate") def custom_normal_sample(mean: float = 0, std: float = 1, size: int = 1) -> np.ndarray: """ 自定义分位的正态类分布采样函数 参数: mean: 采样分布的均值,默认0 std: 采样分布的标准差,默认1 size: 输出样本的数量,默认1 返回: 符合指定分位占比的样本数组 """ # 均匀采样分位值 rand_quantiles = np.random.uniform(0, 1, size=size) # 映射为标准差倍数,再缩放平移到指定均值和标准差 samples = mean + quantile_to_std(rand_quantiles) * std return samples # 测试验证代码 if __name__ == "__main__": # 采样10000个样本,均值10,标准差2 test_samples = custom_normal_sample(mean=10, std=2, size=10000) # 统计各区间占比 within_1std = np.mean(np.abs(test_samples - 10) <= 2) within_2std = np.mean(np.abs(test_samples - 10) <= 4) within_3std = np.mean(np.abs(test_samples - 10) <= 6) print(f"±1σ区间占比: {within_1std:.2%}") print(f"±2σ区间占比: {within_2std:.2%}") print(f"±3σ区间占比: {within_3std:.2%}")
补充说明
- 代码依赖
numpy和scipy,可通过pip install numpy scipy安装依赖 - 3σ外的采样采用线性外推得到,如果你需要限制采样范围不超过±3σ,可将
fill_value参数改为(-3, 3)并设置bounds_error=False - 如果需要更平滑的分布曲线,可在现有分位点之间补充更多自定义映射点,插值方法也可更换为
spline等非线性插值方式
内容的提问来源于stack exchange,提问作者Amit Bharadwa
相关产品推荐
相关产品推荐

