Scipy等库中是否有支持离散/连续分布相加的优化函数?
问题:是否有scipy或其他库的优化函数可以实现概率分布相加
现有多个概率分布,请问scipy(或其他库)中是否存在可用于分布相加的优化函数?参考如下简单示例:
假设我有1个6面骰子和1个20面骰子,需要得到掷出2到26点数对应的概率质量函数。
from scipy.stats import randint import pandas as pd import plotly.express as px x_points_6 = [x+1 for x in range(6)] x_points_20 = [x+1 for x in range(20)] dist_6_sided = [randint.pmf(k,1,7) for k in x_points_6] dist_20_sided = [randint.pmf(k,1,21) for k in x_points_20] total_dist = add_dist(x_points_6, dist_6_sided, x_points_20, dist_20_sided) df = pd.DataFrame({'x':total_dist[0], 'y':total_dist[1]})
我目前自行实现了一个偏暴力计算的分布相加函数:
def add_dist(value1, prob1, value2, prob2): result_value = [] result_prob = [] for prob1_i, value1_i in zip(prob1, value1): for prob2_i, value2_i in zip(prob2, value2): value = value1_i + value2_i prob = prob1_i * prob2_i result_value.append(value) result_prob.append(prob) unique_values = set(result_value) count_x = [] for i in unique_values: count_x.append(result_value.count(i)) return([result_value, result_prob])
通过该函数可以得到最终的分布结果:
df_added_pdfs = df.groupby(['x']).sum() fig = px.bar(df_added_pdfs) fig.show()

我希望找到可以支持scipy内置任意离散或连续分布函数相加的解决方案,不限于简单的均匀分布场景。我猜测可能是搜索关键词不正确没有找到对应功能,这类常规需求应该在scipy或numpy中有内置实现,因此想要寻找更优化的库函数实现方案。
解答
两个独立随机变量和的概率分布本质是各自分布的卷积,numpy和scipy都有高度优化的内置卷积实现,性能远高于手动双重循环实现。
离散分布求和
离散分布的PMF求和直接用numpy.convolve即可,对应你举的骰子示例改造代码如下:
import numpy as np from scipy.stats import randint # 定义两个分布的取值和PMF val_6 = np.arange(1, 7) pmf_6 = randint.pmf(val_6, 1, 7) val_20 = np.arange(1, 21) pmf_20 = randint.pmf(val_20, 1, 21) # 直接计算卷积得到和的PMF sum_pmf = np.convolve(pmf_6, pmf_20, mode="full") # 自动生成和的取值范围 sum_val = np.arange(val_6.min() + val_20.min(), val_6.max() + val_20.max() + 1) # 验证概率和为1 print(sum_pmf.sum()) # 输出1.0,符合概率分布要求
该方案不需要后续手动分组求和,输出结果直接对应每个取值的概率,时间复杂度为O(n+m),远高于现有实现的O(n*m)。如果是非均匀取值的离散分布,先对齐到相同步长的网格再做卷积即可。
连续分布求和
连续分布的PDF求和推荐用scipy.signal.fftconvolve,基于FFT实现,大采样量下性能优势极其明显,示例如下:
import numpy as np from scipy.stats import norm, gamma from scipy.signal import fftconvolve # 定义计算网格,步长越小精度越高 step = 0.01 x = np.arange(-10, 30, step) # 两个连续分布的PDF pdf_norm = norm.pdf(x, loc=0, scale=1) pdf_gamma = gamma.pdf(x, a=2, scale=2) # 卷积计算和的PDF,乘步长做数值积分修正保证概率和为1 sum_pdf = fftconvolve(pdf_norm, pdf_gamma, mode="same") * step sum_x = x
注意事项
以上方法仅适用于相互独立的随机变量,若变量不独立,需要基于联合分布计算,无法直接用卷积实现。如果需要符号推导和的分布闭式解,可以用sympy的概率模块实现。
内容的提问来源于stack exchange,提问作者Docuemada
相关产品推荐
相关产品推荐

