草庐IT

【scipy】Python调用非线性最小二乘法

微小冷 2023-04-21 原文

文章目录

简介与构造函数

在scipy中,非线性最小二乘法的目的是找到一组函数,使得误差函数的平方和最小,可以表示为如下公式

arg min ⁡ f i F ( x ) = 0.5 ∑ i = 0 m − 1 ρ ( f i ( x ) 2 ) , x ∈ [ L , R ] \argmin_{f_i} F(x) = 0.5\sum_{i=0}^{m-1}\rho(f_i(x)^2),\quad x\in[L,R] fiargminF(x)=0.5i=0m1ρ(fi(x)2),x[L,R]

其中 ρ \rho ρ表示损失函数,可以理解为对 f i ( x ) f_i(x) fi(x)的一次预处理。

scipy.optimize中封装了非线性最小二乘法函数least_squares,其定义为

least_squares(fun, x0, jac, bounds, method, ftol, xtol, gtol, x_scale, f_scale, loss, jac_sparsity, max_nfev, verbose, args, kwargs)

其中,funcx0为必选参数,func为待求解函数,x0为函数输入的初值,这两者无默认值,为必须输入的参数。

bound为求解区间,默认 ( − ∞ , ∞ ) (-\infty,\infty) (,)verbose为1时,会有终止输出,为2时会print更多的运算过程中的信息。此外下面几个参数用于控制误差,比较简单。

默认值备注
ftol 1 0 − 8 10^{-8} 108函数容忍度
xtol 1 0 − 8 10^{-8} 108自变量容忍度
gtol 1 0 − 8 10^{-8} 108梯度容忍度
x_scale1.0变量的特征尺度
f_scale1.0残差边际值

loss为损失函数,就是上面公式中的 ρ \rho ρ,默认为linear,可选值包括

  • linear ρ ( z ) = z \rho(z)=z ρ(z)=z,此为标准非线性最小二乘法
  • soft_l1 ρ ( z ) = 2 ( 1 + z − 1 ) \rho(z)=2(\sqrt{1 + z}-1) ρ(z)=2(1+z 1), 相当于L1损失的平滑
  • huber: 当 z ⩽ 1 z\leqslant1 z1时, ρ ( z ) = z \rho(z)=z ρ(z)=z,否则 ρ ( z ) = 2 z − 1 \rho(z)=2\sqrt{z}-1 ρ(z)=2z 1, 表现与soft_l1相似
  • cauchy ρ ( z ) = ln ⁡ ( 1 + z ) \rho(z) = \ln(1 + z) ρ(z)=ln(1+z)
  • arctan ρ ( z ) = arctan ⁡ ( z ) \rho(z) = \arctan(z) ρ(z)=arctan(z)

迭代策略

上面的公式仅给出了算法的目的,但并未暴露其细节。关于如何找到最小值,则需要确定搜索最小值的方法,method为最小值搜索的方案,共有三种选项,默认为trf

  • trf:即Trust Region Reflective,信赖域反射算法
  • dogbox:信赖域狗腿算法
  • lm:Levenberg-Marquardt算法

这三种方法都是信赖域方法的延申,信赖域的优化思想其实就是从单点的迭代变成了区间的迭代,由于本文的目的是介绍scipy中所封装好的非线性最小二乘函数,故而仅对其原理做简略的介绍。

对于优化问题 min ⁡ x ∈ R n f ( x ) \min_{x\in R^n} f(x) minxRnf(x)而言,定义当前点的邻域

Ω k = { x ∈ R n ∣ ∥ x − x k ∥ ⩽ r } \Omega_k=\{x\in R^n\big\vert \Vert x-x_k\Vert\leqslant r\} Ωk={xRn xxkr}

其中 r r r为置信半径,假设在这个邻域内,目标函数可以近似为线性或二次函数,则可通过二次模型得到区间中的极小值点 s k s_k sk。然后以这个极小值点为中心,继续优化信赖域所对应的区间。

s = x − x k s=x-x_k s=xxk, 表示步长; g k = ∇ f ( x k ) , B k ≈ ∇ 2 f ( x k ) g_k=\nabla f(x_k), B_k\approx\nabla^2 f(x_k) gk=f(xk),Bk2f(xk)分别是函数的一阶导数和黑塞矩阵的近似,则对上述问题进行Taylor展开,可以得到一个二阶的近似模型

arg min ⁡ q k ( s ) = f ( x k ) + g k T s + 1 2 s T B k s , ∥ s ∥ ⩽ r \argmin q^{k}(s)=f(x_k)+g_k^Ts+\frac{1}{2}s^TB_ks, \Vert s\Vert\leqslant r argminqk(s)=f(xk)+gkTs+21sTBks,sr

B k B_k Bk被定义为黑塞矩阵的近似,当其表示为雅可比矩阵 J k T J k J_k^TJ_k JkTJk时,所得到的迭代方案便是著名的高斯牛顿法,而LM算法在在高斯牛顿的基础上,添加了一个阻尼因子,可记作 J k T J k + μ I J_k^TJ_k+\mu I JkTJk+μI

狗腿法的鲍威尔提出的一种迭代方案,特点是新定义了下降比,即随着 s s s的不断前进,目标函数和模型函数都会发生变化,则可定义二者的变化率 r k = f ( x k ) − f ( x k + s ) q k ( 0 ) − q k ( s ) r_k=\frac{f(x_k)-f(x_k+s)}{q^k(0)-q^k(s)} rk=qk(0)qk(s)f(xk)f(xk+s),根据这个值的变化,来调整信赖域半径 r r r的值。

以上就是信赖域方法的基本原理。

雅可比矩阵

在了解了信赖域方法之后,就会明白雅可比矩阵在数值求解时的重要作用,而如何计算雅可比矩阵,则是接下来需要考虑的问题。jac参数为计算雅可比矩阵的方法,主要提供了三种方案,分别是基于两点的2-point;基于三点的3-point;以及基于复数步长的cs。一般来说,三点的精度高于两点,但速度也慢一倍。

此外,可以输入自定义函数来计算雅可比矩阵。

测试

最后,测试一下非线性最小二乘法

import numpy as np
from scipy.optimize import least_squares

def test(xs):
    _sum = 0.0
    for i in range(len(xs)):
        _sum = _sum + (1-np.cos((xs[i]*i)/5)*(i+1))
    return _sum

x0 = np.random.rand(5)
ret = least_squares(test, x0)
msg = f"最小值" + ", ".join([f"{x:.4f}" for x in ret.x])
msg += f"\nf(x)={ret.fun[0]:.4f}"
print(msg)
'''
最小值0.9557, 0.5371, 1.5714, 1.6931, 5.2294
f(x)=0.0000
'''

有关【scipy】Python调用非线性最小二乘法的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  5. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  6. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  7. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  10. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

随机推荐