Scipy ODR传入数组型误差时报错:解处矩阵非满秩
scipy.odr传入数组型误差触发“非满秩”错误的解决办法
问题场景
在使用scipy.odr对线性模型执行正交距离回归(ODR)时,若给RealData传入数组型的x、y误差(即每个数据点对应独立的误差值),会触发Problem is not full rank at solution错误。但传入标量误差时程序可正常运行,而业务需求必须使用数组型的逐点误差。
即使使用简单合成数据复现,或参考其他ODR解决方案实现,都会触发该错误。环境版本:Numpy 1.26.4,Scipy 1.13.0。最小复现代码如下:
import numpy as np import scipy.odr as odr import matplotlib.pyplot as plt def odrlin(b, x): return b[0]*x + b[1] linmodel = odr.Model(odrlin) fig, ax = plt.subplots() x = np.linspace(1,10,10) y = 2.8*x + 4.2 y = y*(1 + (np.random.random(len(y))-0.5)*0.2) # y方向添加噪声 xerr, yerr = np.ones(len(x))*x*0.1, np.ones(len(y))*y*0.1 # 10%相对误差 ax.errorbar(x, y, xerr=xerr, yerr=yerr, ls='', marker='.') # 正常运行:标量误差 print('case 1') sx, sy = 0.1, 2 odrdata = odr.RealData(x=x, y=y, sx=sx, sy=sy) myodr = odr.ODR(odrdata, linmodel, beta0=[2,4]) odrout = myodr.run() odrout.pprint() # 报错:数组型相对误差 print('\n case 2') sx, sy = xerr, yerr odrdata = odr.RealData(x=x, y=y, sx=sx, sy=sy) myodr = odr.ODR(odrdata, linmodel, beta0=[2,4]) odrout = myodr.run() odrout.pprint() # 报错:数组型固定误差 print('\n case 3') sx, sy = np.ones(len(x))*0.1, np.ones(len(y))*2 odrdata = odr.RealData(x=x, y=y, sx=sx, sy=sy) myodr = odr.ODR(odrdata, linmodel, beta0=[2,4]) odrout = myodr.run() odrout.pprint()
原因分析
scipy.odr默认使用的'odr'拟合方法(正交距离回归的原生实现)在处理数组型逐点误差时,容易因权重矩阵的构造方式导致信息矩阵秩亏缺,进而触发“非满秩”错误。而标量误差下权重矩阵是对角矩阵且对角元素一致,矩阵结构更稳定,不会出现该问题。
解决方案
显式指定拟合方法为'leastsq'(Levenberg-Marquardt最小二乘法),该方法对数组型权重的兼容性更好,能避免秩亏缺问题。只需在调用run()方法时添加method='leastsq'参数即可。
修改后的验证代码
将case2和case3的run()调用修改为:
odrout = myodr.run(method='leastsq')
修改后重新运行,程序将正常输出拟合结果,不再触发“非满秩”错误。例如case2的输出会包含正确的拟合参数、残差等信息,格式与case1一致。
内容的提问来源于stack exchange,提问作者SCguy
相关产品推荐
相关产品推荐

