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

如何向量化scipy.integrate.nquad被积函数以适配qmc_quad?

问题

现有使用scipy.integrate.nquad计算积分的代码,为提升运算速度想改用scipy.integrate.qmc_quad,但qmc_quad要求被积函数支持向量化,当前函数仅能单次计算一个参数组合,需要对被积函数进行向量化改造以适配qmc_quad。

原代码如下:

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import nquad, qmc_quad


X = [11.3, 14.8, 7.6, 10.5, 12.7, 3.9, 11.2, 5.4, 8.5, 5.0, 4.4, 7.3, 2.9, 5.7, 6.2, 7.3, 3.3, 4.2, 5.5, 4.2]
N = len(X)
I = np.arange(1, N + 1)


def pdf_normal(m1, mn, s1, sn, i, n, x):
    m = (m1 * (n - i) / (n - 1)) + (mn * (i - 1) / (n - 1))
    s = (s1 * (n - i) / (n - 1)) + (sn * (i - 1) / (n - 1))
    y = (x - m) / s
    f = np.exp(-0.5 * y * y) / np.sqrt(2 * np.pi)
    pdf = f / s
    return pdf


def function_g_vec(args):
    [m1, mn, s1, sn] = args
    xi = X
    i = I
    n = N
    values = [pdf_normal(m1, mn, s1, sn, i_val, n, x_val) for i_val, x_val in zip(i, xi)]
    result = np.prod(values)
    return result


limits = [(-10, 30), (-10, 20), (0, 15), (0, 10)]
K = nquad(lambda *x: function_g_vec(x), ranges=limits)
print(K)
# K = 2.9335981345167932e-18
# error_K = 2.9282172140557324e-18
解决方案

核心思路是让被积函数能够处理批量输入的参数组合(即输入是二维数组,每行是一组[m1, mn, s1, sn]),利用numpy的广播机制实现向量化运算,避免循环。

步骤1:向量化改造pdf_normal函数

原函数只能处理单个i和x,改造后让它能同时处理所有i和x的组合,并且支持批量参数输入:

def pdf_normal_vec(m1, mn, s1, sn, i, n, x):
    # m1, mn, s1, sn: 形状为(M,)的数组(M是参数组合数量)
    # i, x: 形状为(N,)的数组(N是样本数量)
    # 利用广播扩展维度,让参数与样本维度匹配
    m = (m1[:, None] * (n - i) / (n - 1)) + (mn[:, None] * (i - 1) / (n - 1))
    s = (s1[:, None] * (n - i) / (n - 1)) + (sn[:, None] * (i - 1) / (n - 1))
    y = (x - m) / s
    f = np.exp(-0.5 * y ** 2) / np.sqrt(2 * np.pi)
    pdf = f / s
    return pdf  # 返回形状为(M, N)的数组,每行对应一组参数的所有样本pdf值

步骤2:改造被积函数适配qmc_quad

让它接受二维数组输入(每行一组参数),并对每组参数计算乘积:

def function_g_qmc(params):
    # params: 形状为(M, 4)的数组,M是批量处理的参数组合数
    m1, mn, s1, sn = params.T  # 拆分出每个参数的数组,形状均为(M,)
    xi = np.array(X)
    i_arr = np.array(I)
    n = N
    # 获取所有参数组合对应的样本pdf值,形状(M, N)
    pdf_vals = pdf_normal_vec(m1, mn, s1, sn, i_arr, n, xi)
    # 对每行(每组参数)计算乘积,得到形状(M,)的结果数组
    result = np.prod(pdf_vals, axis=1)
    return result

步骤3:调用qmc_quad计算积分

qmc_quad要求积分限是一个列表,每个元素是对应维度的(low, high),直接使用原有的limits即可:

# 调用qmc_quad,n_points控制采样点数量(值越大精度越高,速度越慢)
K_qmc, error_qmc = qmc_quad(function_g_qmc, limits=limits, n_points=10000)
print(f"QMC积分结果: {K_qmc}")
print(f"积分误差估计: {error_qmc}")

完整改造后代码

import numpy as np
from scipy.integrate import nquad, qmc_quad


X = [11.3, 14.8, 7.6, 10.5, 12.7, 3.9, 11.2, 5.4, 8.5, 5.0, 4.4, 7.3, 2.9, 5.7, 6.2, 7.3, 3.3, 4.2, 5.5, 4.2]
N = len(X)
I = np.arange(1, N + 1)


def pdf_normal_vec(m1, mn, s1, sn, i, n, x):
    m = (m1[:, None] * (n - i) / (n - 1)) + (mn[:, None] * (i - 1) / (n - 1))
    s = (s1[:, None] * (n - i) / (n - 1)) + (sn[:, None] * (i - 1) / (n - 1))
    y = (x - m) / s
    f = np.exp(-0.5 * y ** 2) / np.sqrt(2 * np.pi)
    pdf = f / s
    return pdf


def function_g_qmc(params):
    m1, mn, s1, sn = params.T
    xi = np.array(X)
    i_arr = np.array(I)
    n = N
    pdf_vals = pdf_normal_vec(m1, mn, s1, sn, i_arr, n, xi)
    return np.prod(pdf_vals, axis=1)


# 原nquad计算(用于对比)
def function_g_vec(args):
    [m1, mn, s1, sn] = args
    xi = X
    i = I
    n = N
    values = [pdf_normal_vec(np.array([m1]), np.array([mn]), np.array([s1]), np.array([sn]), i_val, n, x_val)[0,0] for i_val, x_val in zip(i, xi)]
    result = np.prod(values)
    return result

limits = [(-10, 30), (-10, 20), (0, 15), (0, 10)]
K_nquad, error_nquad = nquad(lambda *x: function_g_vec(x), ranges=limits)
print(f"Nquad积分结果: {K_nquad}")
print(f"Nquad积分误差估计: {error_nquad}")

# QMC计算
K_qmc, error_qmc = qmc_quad(function_g_qmc, limits=limits, n_points=10000)
print(f"\nQMC积分结果: {K_qmc}")
print(f"QMC积分误差估计: {error_qmc}")

关键说明

  • 利用numpy的广播机制:通过[:, None]给参数数组增加一个维度,让它能与样本数组(N维)进行逐元素运算,避免循环。
  • qmc_quad的输入要求:被积函数必须接受形状为(M, d)的二维数组(d是积分维度,这里是4),返回形状为(M,)的数组,每组参数对应一个函数值。
  • 精度与速度:n_points参数控制采样点数量,数值越大精度越高但速度越慢,可根据需求调整。

内容的提问来源于stack exchange,提问作者Alexey_Proz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:05:39