scipy curve_fit分段非线性拟合:依参数选择函数分支问题
解决方案
不需要额外安装其他模块,直接使用numpy自带的向量化条件操作即可适配scipy.optimize.curve_fit的数组传参逻辑。
报错的核心原因是:curve_fit传入的自变量t为numpy数组格式,直接写if theta <= 1.281是尝试对整个布尔数组做单值真值判断,numpy不支持这类隐式转换,因此会抛出要求使用any()/all()的报错。
方法1:使用np.where实现逐元素分支选择(推荐,性能最优)
np.where可以逐元素判断条件,满足条件的位置取第一个分支的计算结果,不满足的取第二个分支的计算结果,完全适配数组运算,修改后的代码如下:
import numpy as np from scipy.optimize import curve_fit def MahonOldham(t, D:'m^2/s', c:'mM'): n = 1 F = 96485 # A s / mol pi = np.pi # 直接调用numpy内置圆周率,比手动写3.14精度更高 a = 12.5 * 10**-6 # m D_scaled = D * 10**-10 # 避免直接修改入参D引发潜在逻辑问题 theta = D_scaled * t / a**2 # 先分别计算两个分段的factor值 factor_low = 1/(np.sqrt(pi*theta)) + 1 + np.sqrt(theta/(4*pi)) - 3*theta/25 + (3*theta**(3/2))/226 factor_high = 4/pi + 8/np.sqrt(pi**5*theta) + 25*theta**(-3/2)/2792 - theta**(-5/2)/3880 - theta**(-7/2)/4500 # 逐元素根据theta阈值选择对应分支的计算结果 factor = np.where(theta <= 1.281, factor_low, factor_high) I = n * pi * F * c * D_scaled * a * factor return I * 10**9
该方法中两个分支的计算会对全量数组执行,再通过np.where筛选有效值,由于numpy向量化运算开销极低,整体运行速度比逐元素循环快几个数量级,是拟合场景下的首选方案。
方法2:使用np.vectorize包装标量逻辑(适合多分支复杂场景)
如果后续分段逻辑更复杂(比如分支数超过2个、判断条件嵌套多),可以先写好支持标量输入的函数逻辑,再用np.vectorize包装成支持数组输入的版本,写法和最初的逻辑几乎一致,缺点是性能比纯numpy向量化运算差:
import numpy as np from scipy.optimize import curve_fit def _MahonOldham_scalar(t, D_scaled, c, pi, a, n, F): theta = D_scaled * t / a**2 if theta <= 1.281: factor = 1/(np.sqrt(pi*theta)) + 1 + np.sqrt(theta/(4*pi)) - 3*theta/25 + (3*theta**(3/2))/226 else: factor = 4/pi + 8/np.sqrt(pi**5*theta) + 25*theta**(-3/2)/2792 - theta**(-5/2)/3880 - theta**(-7/2)/4500 I = n * pi * F * c * D_scaled * a * factor return I * 10**9 def MahonOldham(t, D:'m^2/s', c:'mM'): n = 1 F = 96485 pi = np.pi a = 12.5 * 10**-6 D_scaled = D * 10**-10 # 包装为支持数组输入的向量化版本 calc_vec = np.vectorize(_MahonOldham_scalar, excluded=['D_scaled','c','pi','a','n','F']) return calc_vec(t=t, D_scaled=D_scaled, c=c, pi=pi, a=a, n=n, F=F)
额外注意事项
- 不建议用Python原生for循环逐元素判断计算,数据量稍大时拟合速度会极慢
- 原代码直接修改入参
D *= 10**-10在部分scipy版本下可能引发入参污染的潜在问题,建议单独定义缩放后的D变量 - 手动赋值
pi=3.14精度不足,直接使用np.pi可以避免圆周率精度带来的拟合误差
内容的提问来源于stack exchange,提问作者sylvanas
相关产品推荐
相关产品推荐

