使用scipy integrate模块归一化函数出现结果错误、运行过慢问题
问题原因
1. 性能大幅下降
scipy.integrate.quad做数值积分时,会在积分区间内反复调用被积函数数百次至上千次采样计算。你把区间积分求z的逻辑放到被积函数内部后,每一次采样计算单个x点的取值,都会额外执行一次区间积分操作,相当于嵌套执行了上千次积分,耗时自然上升上百倍。
2. 积分结果不等于1
你写的normalized_chi_1依赖全局变量B,如果B的取值和你积分时的区间不一致(比如函数定义后B被修改、或者定义函数时B未正确赋值),就会导致内部计算的z不是当前目标区间的积分值。比如内部求z时用了卡方分布的全域[0, +∞)作为积分区间,得到z=1,此时被积函数就是原生的chi2.pdf,积分[A,B]得到的结果就是0.4275,和你遇到的现象完全吻合。
另外你提供的代码片段里存在语法错误:quad(chi2.pdf,A,B,args=(df,A)[0]少了右括号,正确写法是quad(chi2.pdf,A,B,args=(df,A))[0],运行前需要修正。
修复方案
如果不想在主流程单独计算维护z变量,可以用闭包实现,保证z只被计算一次,同时避免全局变量依赖:
import numpy as np from scipy.stats import chi2 from scipy.integrate import quad def get_normalized_chi2(A, B, df): # 仅在生成归一化函数时计算一次z,后续调用复用该值 z = quad(chi2.pdf, A, B, args=(df, A))[0] def normalized_func(x): return chi2.pdf(x, df, A) / z return normalized_func # 调用示例 A = 2 B = 4 df = 3 norm_chi2 = get_normalized_chi2(A, B, df) # 积分校验 integral_val = quad(norm_chi2, A, B)[0] print(integral_val) # 输出:1.0
该方案的性能和你最初外置计算z的方案完全一致,同时不需要在主流程单独维护z变量,逻辑更简洁,也不会出现全局变量取值错误的问题。
如果不想用闭包,也可以用缓存装饰器保证z只被计算一次,注意要把B作为参数显式传入函数,不要依赖全局变量:
from functools import lru_cache @lru_cache(maxsize=None) def calc_z(A, B, df): return quad(chi2.pdf, A, B, args=(df, A))[0] def normalized_chi(x, df, A, B): z = calc_z(A, B, df) return chi2.pdf(x, df, A) / z # 校验调用 integral_val = quad(normalized_chi, A, B, args=(df, A, B))[0] print(integral_val)
内容的提问来源于stack exchange,提问作者ivan199415
相关产品推荐
相关产品推荐

