逆变换采样柯西分布时插值超界错误的原因与修正方法
报错原因
报错A value in x_new is above the interpolation range的核心原因是构造的插值函数输入范围根本没有覆盖[0,1]区间:
- 代码中取的x范围是[-6, 6],标准柯西分布在这个区间外的概率约为5.3%,也就是说用
cumsum计算得到的cdf最大值只有约0.947,远小于1;同时cdf的最小值是第一个区间的积分值,也不是0。 - 生成的
cdf_new是[0,1]区间的均匀随机数,只要随机数大于cdf的最大值(≈0.947),就会超出interp1d默认的插值输入范围,触发报错;随机数小于cdf最小值时同样会越界,只是报错优先提示上界越界。 - 额外的小问题:代码用了
from numpy import *的全量导入,后续写np.random会触发命名错误,直接调用random.uniform即可。
修正方案
方案1:保留插值逻辑的修正
调整x的覆盖范围,归一化CDF到[0,1]区间,同时给插值函数设置越界处理规则,避免报错:
from numpy import * from matplotlib.pyplot import * from scipy.interpolate import interp1d def cauchy_pdf(x): return 1 / (pi*(1+x**2)) # 扩大x范围覆盖柯西分布几乎所有支撑集 x = linspace(-1000, 1000, 100000) dx = x[1] - x[0] cdf = cumsum(cauchy_pdf(x)) * dx # 归一化CDF,严格对齐[0,1]范围,消除离散求和的误差 cdf = (cdf - cdf.min()) / (cdf.max() - cdf.min()) # 配置插值函数:关闭越界报错,越界时返回x的端点值 from_cdf_to_x = interp1d(cdf, x, bounds_error=False, fill_value=(x.min(), x.max())) # 生成0-1均匀随机数采样 cdf_new = random.uniform(0, 1, size=10000) x_sampled = from_cdf_to_x(cdf_new) # 采样结果验证 hist(x_sampled, bins=100, density=True, alpha=0.7, range=(-10,10), label='Sampled data') x_plot = linspace(-10, 10, 1000) plot(x_plot, cauchy_pdf(x_plot), 'r', label='Theoretical Cauchy PDF') xlabel('x') ylabel('Density') legend() show()
方案2:使用CDF逆函数解析解(无插值误差,更推荐)
标准柯西分布的CDF有明确解析形式:$F(x) = \frac{1}{2} + \frac{1}{\pi}\arctan(x)$,对应的逆函数可以直接推导,完全不需要插值,精度和效率都更高:
from numpy import * from matplotlib.pyplot import * def cauchy_inverse_cdf(u): # 对CDF求逆得到的解析表达式 return tan(pi * (u - 0.5)) # 采样,裁剪掉u=0和u=1的极端值避免无穷大 cdf_new = random.uniform(0, 1, size=10000) cdf_new = clip(cdf_new, 1e-10, 1-1e-10) x_sampled = cauchy_inverse_cdf(cdf_new) # 采样结果验证 hist(x_sampled, bins=100, density=True, alpha=0.7, range=(-10,10), label='Sampled data') x_plot = linspace(-10, 1000) plot(x_plot, 1/(pi*(1+x_plot**2)), 'r', label='Theoretical Cauchy PDF') xlabel('x') ylabel('Density') legend() show()
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

