如何将Excel实验数据代入最小化目标函数优化系数a,b,c,d?
求解系数a、b、c、d的最优值
实验数据样式

数学建模方程
def equation(oc, a, b, c, d): return np.exp(a) * (np.exp(b*oc[0])) * (np.exp(c*oc[1])) * (np.exp(d*oc[2]))
优化目标
最小化误差,使模型输出贴合实验数据。
现有实现方案
x0 = [1.0, 1.0, 1.0, 1.0] # 定义最小化目标函数 def objective(x): a, b, c, d = x oc = df[['oc1', 'oc2', 'oc3']].values.T y_pred = equation(oc, a, b, c, d) y_true = df['mean'].values.T mse = np.sum((y_pred - y_true) ** 2) return mse # 最小化目标函数 res = minimize(objective, x0, method='Nelder-Mead')
更优雅的实现思路
1. 线性化转换:把非线性问题转成线性回归
原方程是指数乘积形式,可通过取自然对数线性化:
$y = e^a \cdot e^{b \cdot oc_1} \cdot e^{c \cdot oc_2} \cdot e^{d \cdot oc_3}$
取对数后:$\ln(y) = a + b \cdot oc_1 + c \cdot oc_2 + d \cdot oc_3$
这就变成了标准多元线性回归问题,计算效率远高于非线性优化,结果还能作为后续精细优化的初始值,提升收敛速度。示例代码:
import numpy as np from sklearn.linear_model import LinearRegression from scipy.optimize import minimize # 预处理数据:对目标值取对数 X = df[['oc1', 'oc2', 'oc3']].values y_log = np.log(df['mean'].values) # 训练线性回归模型 linear_model = LinearRegression(fit_intercept=True) linear_model.fit(X, y_log) # 提取初始参数:截距对应a,系数对应b、c、d x0 = [linear_model.intercept_, *linear_model.coef_] # 提前预处理重复使用的数据 oc = df[['oc1', 'oc2', 'oc3']].values.T y_true = df['mean'].values.T def mse_loss(x): a, b, c, d = x y_pred = np.exp(a) * np.exp(b*oc[0]) * np.exp(c*oc[1]) * np.exp(d*oc[2]) return np.sum((y_pred - y_true) ** 2) # 用线性回归结果作为初始值做精细优化 res = minimize(mse_loss, x0, method='Nelder-Mead')
2. 用曲线拟合专用工具简化代码
使用scipy.optimize.curve_fit,语法更贴合曲线拟合场景,无需手动封装目标函数:
from scipy.optimize import curve_fit # 适配curve_fit的参数顺序:自变量在前,模型参数在后 def exponential_model(oc, a, b, c, d): oc1, oc2, oc3 = oc return np.exp(a) * np.exp(b*oc1) * np.exp(c*oc2) * np.exp(d*oc3) # 准备输入数据:自变量以元组形式传入 x_data = (df['oc1'].values, df['oc2'].values, df['oc3'].values) y_data = df['mean'].values # 可传入线性回归得到的初始值提升拟合效果 popt, pcov = curve_fit(exponential_model, x_data, y_data, p0=x0) # popt即为最优参数[a, b, c, d]
3. 性能与可读性优化
- 提前预处理数据:避免在优化迭代中重复读取、转换数据,减少计算开销;
- 选择梯度优化器:如果目标函数可导(可通过自动微分工具如Jax计算梯度),使用
L-BFGS-B或trust-constr等梯度类优化器,收敛速度和精度优于Nelder-Mead:
import jax.numpy as jnp from jax import grad from scipy.optimize import minimize def mse_loss_jax(x): a, b, c, d = x y_pred = jnp.exp(a) * jnp.exp(b*oc[0]) * jnp.exp(c*oc[1]) * jnp.exp(d*oc[2]) return jnp.sum((y_pred - y_true) ** 2) # 自动计算梯度 grad_loss = grad(mse_loss_jax) res = minimize(mse_loss_jax, x0, method='L-BFGS-B', jac=grad_loss)
- 命名规范化:将
objective改为mse_loss,equation改为exponential_model,提升代码可读性; - 封装复用:将数据预处理、模型拟合逻辑封装成函数或类,方便后续维护和复用。
内容的提问来源于stack exchange,提问作者newtopy
相关产品推荐
相关产品推荐

