能否无需for循环使用curve_fit对多组信号进行曲线拟合?
无需for循环实现矩阵多列数据的曲线拟合
要直接对矩阵每列的信号组执行拟合,得到形状为2×N的参数数组,你可以通过向量化改造拟合函数来实现,避免使用for循环。以下是具体方案:
问题分析
原代码直接将矩阵y传入curve_fit会报错,因为默认情况下curve_fit期望y是一维数组,会尝试用一组参数拟合所有数据,而非为每列数据单独拟合一组参数。我们需要改造拟合函数,让它支持同时处理多组参数和多列y数据。
实现方案
1. 改造拟合函数,支持向量化计算
修改线性拟合函数,使其能接受数组形式的参数,利用numpy广播特性匹配y的矩阵形状:
def affine_vec(x, a, b): # x: 形状(M,)的自变量数组 # a、b: 形状(N,)的参数数组,对应N组拟合的斜率和截距 # 返回形状(M,N)的拟合结果,与输入y的形状一致 return a[np.newaxis, :] * x[:, np.newaxis] + b[np.newaxis, :]
2. 执行向量化拟合
初始化多组参数的初始值,拟合后将结果重塑为2×N的形状:
# 获取y的列数(即待拟合的信号组数) n_groups = y.shape[1] # 初始化所有组的参数初始值:每组都是[a_est=9, b_est=-1],展平为一维数组 p0 = np.tile([9, -1], n_groups) # 执行拟合:x是一维数组,y是(M,N)的矩阵 popt, pcov = curve_fit(affine_vec, x, y, p0=p0) # 将一维的popt重塑为(2, N)的形状:第一行是所有组的a,第二行是所有组的b popt = popt.reshape(2, n_groups) # 打印结果,对比原for循环的输出 print("向量化拟合得到的参数数组:") print(popt)
完整可运行代码
# -*- coding: utf-8 -*- import matplotlib.pyplot as plt import matplotlib as mpl mpl.use('Qt5Agg') import numpy as np from scipy.optimize import curve_fit def affine(x, a, b): return a*x + b # 改造后的向量化拟合函数 def affine_vec(x, a, b): return a[np.newaxis, :] * x[:, np.newaxis] + b[np.newaxis, :] x = np.arange(0,100,10) a = 10 b = -2 y = np.array([affine(x, a+i, b) + np.random.normal(0,20,x.shape) for i in range(10)]).T plt.figure() plt.plot(x,y) # 原for循环拟合(用于对比) print("原for循环拟合结果:") for i in range(10): a_est = 9 b_est = -1 popt_loop, pov_loop = curve_fit(affine, x, y[:,i], p0 = [a_est, b_est] ) print(i, popt_loop) # 向量化拟合(无for循环) print("\n向量化拟合结果:") n_groups = y.shape[1] p0 = np.tile([9, -1], n_groups) popt_vec, pcov_vec = curve_fit(affine_vec, x, y, p0=p0) popt_vec = popt_vec.reshape(2, n_groups) print(popt_vec)
结果说明
- 向量化拟合得到的
popt_vec形状为(2,10),完全符合需求:第一行是10组信号的斜率a估计值,第二行是截距b估计值。 - 该方法的拟合结果和原for循环的结果完全一致,同时避免了循环带来的冗余代码,效率更高。
内容的提问来源于stack exchange,提问作者ymmx
相关产品推荐
相关产品推荐

