问题陈述
目标
您似乎想解决以下非线性最小二乘问题。
查找给定函数的常量c1 和c2:
例如它可以最大限度地减少平方误差 w.r.t。实验数据集。
挑战
您已经在scipy 包中选择了正确的工具,您实现了解决问题的逻辑,并且您指的是在图形界面(Qt5)中运行您的程序时的一些阻塞过程。
但是我们错过了试验数据集和框架返回的错误。那肯定会有所帮助。
无论如何,在调查您的问题时,我发现至少有两个关键点需要解决:
- 确保曲线拟合算法收敛;
- 确保 ad hoc 方法签名。
观察
当使用一些潜在的数据集运行你的 sn-p 时,我得到:
OptimizeWarning: Covariance of the parameters could not be estimated
这表明问题可能是病态的,可能不会收敛到所需的解决方案。
当我尝试一次将它应用于多个点时,我得到:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
这表明函数调用中某处存在签名错误。
MCVE
目标函数和数据集
让我们定义目标函数和试验数据集来进行讨论。
首先我们定义订单n的Debye function:
import numpy as np
from scipy import integrate, optimize
import matplotlib.pyplot as plt
def Debye(n):
def integrand(t):
return t**n/(np.exp(t) - 1)
@np.vectorize
def function(x):
return (n/x**n)*integrate.quad(integrand, 0, x)[0]
return function
注意包装函数上的@np.vectorize 装饰器。它将阻止上面引用的ValueError。
然后我们根据3阶德拜函数定义目标函数:
debye3 = Debye(3)
def objective(x, c, theta):
return c*(x/theta)*debye3(x/theta)
最后,我们创建了一个实验设置,观察结果存在一些正常错误:
np.random.seed(123)
T = np.linspace(200, 400, 21)
c1 = 1e-1
c2 = 298.15
sigma = 5e-4
f = objective(T, c1, c2)
data = f + sigma*np.random.randn(f.size)
优化
然后我们可以执行优化程序:
parameters, covariance = optimize.curve_fit(objective, T, data, (0, 300))
对于试验数据集,它返回:
(array([1.02509632e-01, 3.10534004e+02]),
array([[1.85637330e-06, 9.46948796e-03],
[9.46948796e-03, 4.92873904e+01]]))
这似乎是一个相当可接受的调整。
现在您可以在拟合范围内插入任何点。从图形上看是这样的:
Tlin = np.linspace(200, 400, 201)
fhat = objective(Tlin, *parameters)
fig, axe = plt.subplots()
axe.plot(T, data, '.', label="Data")
axe.plot(Tlin, fhat, '-', label="Fit")
# ...
请注意,我们在 curve_fit 方法中添加了初始猜测,以使其收敛到正确的最优值。
这在您的 sn-p 中缺失,可能会阻止您的过程以可接受的迭代次数收敛或达到所需的最优值。
实时调频
阅读文档,方法cureve_fit可以提出:
-
ValueError:如果 ydata 或 xdata 包含 NaN,或者使用了不兼容的选项;
-
RuntimeError:如果最小二乘最小化失败;
-
OptimizeWarning: 如果无法估计参数的协方差。
结论
在为机器定义问题时,拟合曲线需要一些创造力和非常小心。
要解决您的问题,您当然需要注意:
- 防止调用不匹配的方法签名和参数提要;
- 确保稳定性和收敛性的优化方法(问题实现、集成方法、优化方法、初始猜测);
- 解决流程引发的所有错误和警告(它会告诉您问题出在哪里,即使它们乍一看很神秘,也不要忽略它们);
- 使用拟合元数据(例如:参数协方差、MSE)验证结果。
检查清单完成后,问题可能就解决了。