使用scipy.signal.deconvolve进行高斯分布反卷积未得预期结果的技术求助
使用scipy.signal.deconvolve进行高斯分布反卷积未得预期结果的技术求助
看起来你遇到的问题核心是用错了工具——scipy.signal.deconvolve根本不是为概率分布的反卷积场景设计的,咱们一步步拆解问题和解决办法:
为什么scipy.signal.deconvolve不适用?
- 这个函数是针对信号处理领域的线性系统反卷积设计的,它的核心模型是「输出信号 = 输入信号 卷积 系统脉冲响应」,目的是还原输入信号或系统响应,和概率分布的卷积逻辑完全不同。
- 概率分布的卷积是积分意义下的连续卷积,而
scipy.signal.deconvolve处理的是离散线性卷积,两者的数学定义存在本质差异;另外概率PDF的数值通常很小,反卷积过程中容易放大数值噪声,直接导致结果完全偏离预期。
正确的概率反卷积实现方法:傅里叶变换法
由于卷积在频域对应乘积,反卷积自然可以通过频域相除+逆傅里叶变换来实现,这是概率分布反卷积的通用方法(不管是不是高斯分布都适用)。具体逻辑是:
- 对X和Z的PDF序列做快速傅里叶变换(FFT)
- 频域上用Z的FFT结果除以X的FFT结果(为了避免除以零,可以给分母加一个极小的epsilon)
- 对相除后的结果做逆FFT,取实部(数值计算可能引入微小虚部,直接忽略即可)
修改后的代码示例
import numpy as np import scipy.stats import matplotlib.pyplot as plt dx = 1e-1 grid = np.arange(-20, 30, dx) # 定义已知分布 dist_X = scipy.stats.norm(loc=20, scale=4) dist_Z = scipy.stats.norm(loc=0, scale=5) # 理论上的Y分布 dist_Y_true = scipy.stats.norm(loc=-20, scale=np.sqrt(5**2 - 4**2)) # 获取PDF序列 Z_signal = dist_Z.pdf(grid) X_signal = dist_X.pdf(grid) Y_true_signal = dist_Y_true.pdf(grid) # 用傅里叶变换实现反卷积 epsilon = 1e-12 # 避免除以零的极小值 Z_fft = np.fft.fft(Z_signal) X_fft = np.fft.fft(X_signal) Y_fft = Z_fft / (X_fft + epsilon) Y_signal = np.fft.ifft(Y_fft).real # 归一化(数值计算可能导致积分不为1,修正为合法PDF) Y_signal /= np.trapz(Y_signal, dx=dx) # 画图对比 plt.figure(figsize=(8, 6)) plt.plot(grid, Y_signal, label=r'$Y$ (反卷积结果)') plt.plot(grid, Y_true_signal, label=r'$Y$ (理论值)', linestyle='--') plt.plot(grid, X_signal, label=r'$X$') plt.plot(grid, Z_signal, label=r'$Z$') plt.legend(fontsize='16') plt.grid(axis='x', color='0.95') plt.grid(axis='y', color='0.95') plt.ylabel(r'PDF', fontsize='20') plt.xlabel(r'取值', fontsize='20') plt.show()
额外说明
- 对于非高斯分布,只要其PDF是可傅里叶变换的,这个方法同样适用;
- 注意采样网格的范围和步长:要确保网格覆盖三个分布的主要概率区间,步长太小会增加计算量,太大则会损失精度;
- 归一化步骤很重要:数值计算过程中FFT/逆FFT可能会让结果的积分偏离1,用
trapz积分归一化后才能得到合法的PDF。
备注:内容来源于stack exchange,提问作者Maveryck Andres Garzon Espejo
相关产品推荐
相关产品推荐

