用数值方法求解非线性方程组

我需要在我的Java程序中解决非线性最小化(N个未知数的最小残差平方)问题。 解决这些问题的常用方法是Levenberg-Marquardt算法。 我有一些问题

  • 有没有人对不同的LM实现有经验? LM的味道略有不同,我听说算法的确切实现对其数值稳定性有重要影响。 我的function非常好,所以这可能不是问题,但当然我想选择一个更好的选择。 以下是我发现的一些替代方案:

    • FPL统计小组的非线性优化Java包 。 这包括经典Fortran MINPACK例程的Java转换。

    • JLAPACK ,另一个Fortran翻译。

    • 优化算法工具包 。

    • Javanumerics 。

    • 一些Python实现。 纯Python很好,因为它可以用jythonc编译成Java。

  • 是否有任何常用的启发式方法来进行LM所需的初始猜测?

  • 在我的应用程序中,我需要对解决方案设置一些约束,但幸运的是它们很简单:我只是要求解决方案(为了成为物理解决方案)是非负的。 稍微负面的解决方案是数据中测量不准确的结果,显然应该为零。 我正在考虑使用“常规”LM但迭代,以便如果一些未知数变为负数,我将其设置为零并从中解决其余部分。 真正的数学家可能会嘲笑我,但你认为这可行吗?

感谢您的任何意见!

更新 :这不是火箭科学,要解决的参数数量(N)最多为5,数据集几乎不足以使解决成为可能,所以我相信Java足以解决这个问题。 而且我相信聪明的应用数学家已经多次解决了这个问题,所以我只是在寻找一些现成的解决方案,而不是自己做饭。 例如,如果它是纯Python,Scipy.optimize.minpack.leastsq可能会没问题。

您的初始猜测越接近解决方案,您收敛的速度就越快。

你说这是一个非线性问题。 你可以做一个线性化的最小二乘解。 也许您可以使用该解决方案作为第一个猜测。 一些非线性迭代会告诉你一些关于假设的好坏的信息。

另一个想法是尝试另一种优化算法。 如果您可以在许多CPU上运行它们,遗传和蚁群算法可能是一个不错的选择。 它们也不需要连续的导数,所以如果你有离散的,不连续的数据它们会很好。

如果问题有限制,则不应使用无约束求解器。 例如,如果知道你的一些变量必须是非负的,你应该告诉你的解算器。

如果您乐意使用Scipy,我建议使用scipy.optimize.fmin_l_bfgs_b您可以使用L-BFGS-B在变量上放置简单边界。

注意,L-BFGS-B采用一般的非线性目标函数,而不仅仅是非线性最小二乘问题。

我同意codehippo; 我认为解决约束问题的最佳方法是使用专门设计来处理它们的算法。 在这种情况下,L-BFGS-B算法应该是一个很好的解决方案。

但是,如果在你的情况下使用python的scipy.optimize.fmin_l_bfgs_b模块不是一个可行的选项(因为你使用的是Java),你可以尝试使用我编写的库:L-BFGS的原始Fortran代码的Java包装器-B算法。 您可以从http://www.mini.pw.edu.pl/~mkobos/programs/lbfgsb_wrapper下载它,看看它是否符合您的需求。

FPL包非常可靠,但有一些怪癖(数组访问从1开始),因为它对旧的fortran代码有非常直接的解释。 如果您的函数表现良好,LM方法本身就非常可靠。 强制非负约束的一种简单方法是直接使用参数的平方而不是参数。 这可能会引入虚假解决方案,但对于简单模型,这些解决方案很容易被筛选出来。

有一个“约束”LM方法可用的代码。 在这里查看http://www.physics.wisc.edu/~craigm/idl/fitting.html for mpfit。 有一个python(遗憾地依赖于Numeric)和一个C版本。 LM方法大约有1500行代码,因此您可能倾向于将C移植到Java。 实际上,“约束”LM方法与您设想的方法没有太大区别。 在mpfit中,代码相对于变量的边界调整步长。 我也用mpfit取得了不错的成绩。

我对BFGS没有那么多经验,但是代码要复杂得多,而且我从来都不清楚代码的许可。

祝你好运。

我实际上并没有使用任何这些Java库,所以请考虑一下:基于后端,我可能会首先看一下JLAPACK。 我相信LAPACK是Numpy的后端,它实际上是在Python中进行线性代数/数学操作的标准。 至少,你肯定应该使用经过良好优化的C或Fortran库而不是纯Java,因为对于大型数据集,这些类型的任务可能会非常耗时。

为了创建初始猜测,它实际上取决于您尝试适合的function类型(以及您拥有的数据类型)。 基本上,只需寻找一些相对较快(可能是O(N)或更好)的计算,它将为您想要的参数提供近似值。 (我最近用Numpy中的高斯分布做了这个,我估计平均值只是average(values, weights = counts) – 也就是直方图中计数的加权平均值,这是数据集的真实均值。它不是我正在寻找的峰值的确切中心,但它已经足够接近了,算法在剩下的路上完成了。)

至于保持积极的约束,你的方法似乎是合理的。 由于您正在编写一个程序来完成工作,因此可能只需创建一个布尔标志,以便您轻松启用或禁用“强制 – 非负”行为,并以两种方式运行它进行比较。 只有当你遇到很大的差异时(或者如果一个版本的算法花费的时间过长),可​​能需要担心。 (真正的数学家会从头开始分析最小二乘最小化;-P所以我认为你是那个可以嘲笑他们的人……开玩笑。也许吧。)