You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询:如何使用SciPy的QMC(Sobol)生成多个非同分布的拟随机变量

咨询:如何使用SciPy的QMC(Sobol)生成多个非同分布的拟随机变量

问题描述

我现在在用SciPy的拟蒙特卡洛(QMC)工具做函数估计,目标是构建多变量函数的生存函数,函数形式如下:
$Y = c_1f_1(X_1) + c_2f_2(X_2) + c_3f_3(X_3)…$
其中:

  • $c_1,c_2,c_3$ 是常数
  • $f_1,f_2,f_3$ 等是函数(大多线性,但也有例外)
  • $X_1,X_2,X_3$ 等是独立但非同分布的随机变量,各自的分布大多不一样

常规蒙特卡洛的方案我已经搞定了:生成对应分布的随机数代入公式就行。但换成QMC(比如Sobol序列)就卡壳了——如果变量都是同分布的,我知道怎么用qmc_engine参数直接生成,但现在每个变量分布都不同,试了重复调用同一个Sobol引擎生成不同分布的序列,结果相关性太强完全没用。虽然想到过用[0,1]均匀拟随机样本再映射到目标分布,但感觉SciPy的QMC文档既然强调支持不同分布,应该有更直接的正确姿势,求指点!

解决方案

嘿,这个问题我之前踩过坑!核心思路其实很清晰:用一个高维的Sobol引擎,把每个维度对应到一个目标分布的逆CDF(分位数函数)转换,这样既能保证每个变量的分布正确,又能完整保留QMC的低差异特性。

具体实现步骤&代码示例

假设你需要3个不同分布的随机变量:Fisk(3.9)、正态分布N(0,2)、Beta(2,5),代码可以这么写:

import scipy.stats as stats
from scipy.stats import qmc
import numpy as np

# 1. 确定变量数量和需要生成的样本量
num_vars = 3
sample_size = 1000

# 2. 初始化对应维度的Sobol引擎(必须用高维,不能单维度重复调用!)
sobol_engine = qmc.Sobol(d=num_vars, scramble=True)
# 生成[0,1)^num_vars的高维均匀拟随机样本
uniform_samples = sobol_engine.random(n=sample_size)

# 3. 定义每个变量对应的目标分布(按维度顺序对应)
target_dists = [
    stats.fisk(3.9),       # 第1个变量的分布
    stats.norm(loc=0, scale=2),  # 第2个变量的分布
    stats.beta(a=2, b=5)  # 第3个变量的分布
]

# 4. 对每个维度的均匀样本做分位数转换,得到目标分布的拟随机样本
qmc_samples = []
for dim_idx in range(num_vars):
    # 用对应分布的分位数函数(ppf)把[0,1]均匀样本转成目标分布样本
    dim_samples = target_dists[dim_idx].ppf(uniform_samples[:, dim_idx])
    qmc_samples.append(dim_samples)

# 转成方便使用的格式:每一行是一组(X1,X2,X3)样本
qmc_samples = np.array(qmc_samples).T

关键细节解释

  1. 为什么要用高维引擎?
    Sobol序列的低差异特性是基于高维空间的均匀分布设计的,如果重复调用单维度引擎,会导致不同变量的序列维度重叠,产生严重的相关性,完全破坏QMC的优势。用一个和变量数同维度的引擎,每个维度独立对应一个变量,才能保证样本的低差异特性。

  2. 分位数转换的合理性
    这个方法本质上和你想到的“均匀映射”是一致的,但更贴合SciPy QMC的设计逻辑:Sobol引擎负责生成低差异的均匀样本,每个维度的分位数转换(ppf)把均匀样本映射到目标分布,因为转换是单调的,不会破坏原样本的低差异特性,同时保证每个变量的分布符合要求。

  3. 自定义分布的处理
    如果你的某些分布是自定义的(没有内置ppf),可以用scipy.stats.sampling.NumericalInverseHermite先拟合出该分布的数值逆CDF,然后用这个逆CDF来替代ppf做转换,比如:

    # 自定义分布示例:比如用NumericalInverseHermite拟合一个分布
    custom_dist = stats.fisk(3.9)  # 这里替换成你的自定义分布
    inv_cdf = stats.sampling.NumericalInverseHermite(custom_dist)
    # 对对应维度的均匀样本做转换
    dim_samples = inv_cdf.ppf(uniform_samples[:, dim_idx])
    

验证小技巧

你可以用scipy.stats.qmc.discrepancy函数分别计算转换前后样本的差异度,确认转换后的样本依然保持了QMC的低差异特性,对比普通蒙特卡洛样本的差异度,就能看到效果啦!

备注:内容来源于stack exchange,提问作者Vermin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:47:57