如何用Scipy拟合含未知形状参数矩阵C的函数?
拟合动态形状系数矩阵的二元多项式方案
核心问题是scipy的拟合函数仅支持一维参数数组,而你的系数矩阵C是运行时确定形状的二维结构(甚至可能每行长度不一致)。解决方案是将C扁平化作为拟合参数,同时提前记录C的形状信息,在拟合函数内部将参数恢复为原结构。
方案一:使用scipy.optimize.curve_fit
步骤说明
- 提取
C的形状信息:行数、每行的列数列表 - 用闭包封装形状信息,生成符合
curve_fit要求的目标函数(输入为自变量数组+扁平化参数,输出为预测值数组) - 将初始
C扁平化作为初始参数,执行拟合 - 将拟合得到的扁平化参数恢复为原
C结构
代码示例
import numpy as np from scipy.optimize import curve_fit def make_fit_func(rows, cols_per_row): """生成拟合用的目标函数,封装C的形状信息""" def fit_func(x, *params): x0, x1 = x # 将扁平化参数恢复为C的结构 C = [] idx = 0 for cols in cols_per_row: row = np.array(params[idx:idx+cols]) C.append(row) idx += cols # 向量化计算预测值(避免循环样本,提升效率) result = 0.0 for i in range(rows): # 计算x0的各次幂:shape=(样本数, 该行列数) x0_pows = x0[:, None] ** np.arange(cols_per_row[i]) # 计算x1的i次幂:shape=(样本数,) x1_pow = x1 ** i # 累加该行的贡献 result += (x0_pows @ C[i]) * x1_pow return result return fit_func # ---------------------- 示例:生成测试数据 ---------------------- # 真实系数矩阵(形状运行时确定) true_C = [[1.2, 0.8], [0.9]] rows = len(true_C) cols_per_row = [len(row) for row in true_C] # 扁平化初始参数(可加噪声模拟初始猜测) initial_params = np.concatenate(true_C) + np.random.normal(0, 0.1, size=len(np.concatenate(true_C))) # 生成自变量样本 x0 = np.linspace(0, 5, 100) x1 = np.linspace(0, 3, 100) # 生成带噪声的目标值 y_true = [] for xi, yi in zip(x0, x1): r = 0 for i in range(rows): for j in range(len(true_C[i])): r += xi**j * yi**i * true_C[i][j] y_true.append(r) y = np.array(y_true) + np.random.normal(0, 0.2, size=len(y_true)) # ---------------------- 执行拟合 ---------------------- fit_func = make_fit_func(rows, cols_per_row) popt, pcov = curve_fit(fit_func, (x0, x1), y, p0=initial_params) # 将拟合参数恢复为C结构 fitted_C = [] idx = 0 for cols in cols_per_row: fitted_C.append(popt[idx:idx+cols].tolist()) idx += cols print("真实C:", true_C) print("拟合C:", fitted_C)
方案二:使用scipy.optimize.least_squares
least_squares需要残差函数(预测值与真实值的差),思路与curve_fit一致,仅需调整函数签名为接受扁平化参数,返回残差数组。
代码示例
import numpy as np from scipy.optimize import least_squares def make_residual_func(x0, x1, y_true, rows, cols_per_row): """生成残差函数,封装数据和C的形状信息""" def residual_func(params): # 将扁平化参数恢复为C的结构 C = [] idx = 0 for cols in cols_per_row: row = np.array(params[idx:idx+cols]) C.append(row) idx += cols # 向量化计算预测值 result = 0.0 for i in range(rows): x0_pows = x0[:, None] ** np.arange(cols_per_row[i]) x1_pow = x1 ** i result += (x0_pows @ C[i]) * x1_pow # 返回残差 return result - y_true return residual_func # 使用示例数据(同方案一) residual_func = make_residual_func(x0, x1, y, rows, cols_per_row) result = least_squares(residual_func, initial_params) # 恢复拟合的C结构 fitted_C_ls = [] idx = 0 for cols in cols_per_row: fitted_C_ls.append(result.x[idx:idx+cols].tolist()) idx += cols print("least_squares拟合C:", fitted_C_ls)
关键注意点
- 若样本量较大,务必使用向量化计算替代循环,避免性能瓶颈
- 初始参数
p0需根据实际情况合理设置,若初始值偏离过大可能导致拟合失败 - 对于不规则形状的
C(如示例中的[[1.,1.],[1.]]),代码同样适用,只需正确传递cols_per_row列表即可
内容的提问来源于stack exchange,提问作者Bagnarol
相关产品推荐
相关产品推荐

