python - 具有大量数字的最小二乘优化
问题描述
我有以下功能,我需要尽量减少使用最小二乘法(我正在使用 lmfit)。
y = a * exp(-x/b) + c
例如,我有以下数据:
profitlist = [-10000, 100.00, 1000.00, 100000.00, 1000000.00]
utilitylist = [0, 0.2, 0.4, 0.6, 1]
应用程序返回以下错误:
ValueError: NaN values detected in your input data or the output of your objective/model function - fitting algorithms cannot handle this! Please read https://lmfit.github.io/lmfit-py/faq.html#i-get-errors-from-nan-in-my-fit-what-can-i-do for more information.
问题似乎是:如果 profitList 包含任何更大的负数(-1000 有效,-100000 无效),则exp(-x/b)返回inf或-inf 。所以它可能会溢出。
ProfitList 中的值可以是非常大的浮点数,并且它们并不总是相同的。那么如何用这些巨大的数字来优化它呢?似乎 lmfit 不支持可以解决问题的十进制数字......我该怎么做才能让它工作?
class LeastSquares:
def __init__(self, profitList, utilityList):
self.profitList = np.asarray(profitList)
self.utilityList = np.asanyarray(utilityList)
def function(self, params, x):
a = params["a"]
b = params["b"]
c = params["c"]
return a * np.exp(-x/b) + c
def residual(self, params, x, y):
return (y - self.function(params, x))**2
def setParameters(self, a_start, b_start, c_start):
parameters = Parameters()
parameters.add(name="a", value=a_start, min=None, max=0, vary=True)
parameters.add(name="b", value=b_start, vary=True, min=0.1, max=None)
parameters.add(name="c", value=c_start, vary=True)
return parameters
def startOptimalization(self):
parameters = self.setParameters(-1, 1, 1)
result = minimize(self.residual, parameters, args=(self.profitList, self.utilityList), method="leastsq")
result.params.pretty_print()
print(fit_report(result))
print("SSE")
print(np.sum(result.residual))
解决方案
如您所见,numpy.exp(arg)
对于大于 ~709 的任何参数都给出 Infinity,您需要避免这种极端值。底层求解器根本无法解决它们。既然你的论点arg
是-x/b
,你需要确保它b
不会小到把论点炸毁numpy.exp()
。
b
事实上,您的代码显示您确实设置了0.1的下限。
但是随着值profitlist
扩展到 1e7,该下限太小而无法阻止 Infinity - 您的下限b
必须在 14,000 左右。
如果每次优化运行时您的值profitlist
都在变化,您可能需要执行以下操作(在您的 中startOptimization
):
parameters = self.setParameters(-1, 1, 1)
parameters['b'].min = max(abs(self.profitList))/700.0
result = minimize(self.residual, parameters, args=(self.profitList, self.utilityList), method="leastsq")
result.params.pretty_print()
此外,在拟合指数变化时,计算指数模型函数通常很有帮助,然后将残差作为数据的对数和模型的对数,有效地在对数空间中进行拟合,就像您可能会绘制的那样数据。
最后,不要自己取差的平方或平方和,只需返回带有符号的残差数组。也就是说,你可能会更好地使用类似的东西:
def residual(self, params, x, y):
return np.log(y) - np.log(self.function(params, x))
推荐阅读
- java - 使用 GUI 时的错误:IllegalStateException
- c# - ?: 后面有两个声明的三元运算符
- javascript - 通过 ReactJS 消费 JSON 数据
- javascript - 异步调用不评估反应中的条件
- javascript - Dynamics365“查找控件错误:无法将 typename= 的项目添加到查找控件”JavaScript 错误
- django-simple-history - 无法设置/读取 Django 简单历史更改原因
- docker - 为什么要求在 Kubernetes PodSecurityPolicy 冗余中删除所有功能,非 root + 禁止特权升级?
- laravel - 如何使用foreach,laravel在视图中显示?
- ssis - SSIS - 仅移动 SQL 命令中返回的文件名
- c# - 将带下划线的字符串转换为 TitleCase