前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零开始学量化(六):用Python做优化

从零开始学量化(六):用Python做优化

作者头像
量化小白
发布2019-07-30 17:52:05
6.1K0
发布2019-07-30 17:52:05
举报
文章被收录于专栏:量化小白上分记

优化问题是量化中经常会碰到的,之前写的风险平价/均值方差模型最终都需要解带约束的最优化问题,本文总结用python做最优化的若干函数用法。

首先说明,本文仅把python看作一种工具,说明如何用python求解优化问题,不过多考虑由于模型方法导致的精度、速度、适用性等问题,具体问题还需要具体分析,选择适当的方法,或者自己手写。

python中最常用的做最优化的模块是scipy.optimize,这里只说明这一模块的使用,其他的略过。

根据官方文档的说明,scipy.optimze的功能涉及5方面:

  • 无约束和带约束的多元优化算法(minimize)
  • 全局最优化(basinhopping,differential_evolution等)
  • 最小二乘优化(least_squares)和曲线拟合(curve_fit)
  • 一元优化问题(minimize_scalar)和一元方程数值解(root_scalar)
  • 多元方程求根(root)

1,4中得到的是给定区间内的局部最优解,2中得到的是全局最优解,每个函数下有若干方法可以选择。当然求解一元的优化问题也可以用minimize,但尝试过之后发现用minimize_scalar的速度要更快一些,下面具体说明

一元优化问题

用minimize_scalar解一元优化。一元优化问题可以表述如下

f是优化目标,a,b是自变量的取值范围,也可以没有或只有上界或下界,g是自变量可能有的其他约束。如果有g(x)约束,不能用minimize_scalar,只能用minimize

minimize_scalar用法如下

代码语言:javascript
复制
scipy.optimize.minimize_scalar(fun, bracket=None,
bounds=None, args=(), method='brent', tol=None,
options=None)

fun:优化目标函数

method:优化的方法,有"brent"、'bounded、'golden'三种,也支持自定义。

bracket:一个bracketing区间,'brent','golden'这两种方法中用到,不设定也可以。

bounds:自变量区间,对应上面的a,b,只在method='bounded'时有效

tol,options:设定优化的参数,最小误差、最大迭代次数、是否返回每步的结果等。

args:优化函数的其他输入参数

只需要注意,如果自变量x没有区间设定,直接用默认的就可以了,如果x有区间约束,必须用'bounded'方法。

举个例子:

返回值的fun是最优函数值,x是最优自变量,可以看出,method取brent时,设定区间没什么用。

多元优化问题

多元优化问题的表述跟一元基本一致,把x理解成向量就可以了,求解这一类问题可以用minimize函数。

代码语言:javascript
复制
scipy.optimize.minimize(fun, x0, args=(), method=None,
jac=None, hess=None, hessp=None, bounds=None, constraints=(),
tol=None, callback=None, options=None)

参数很多,比较重要的包括fun,x0,method,bounds,constraints,其他的可有可无。像jac,hess是求解过程中计算梯度和计算hessian矩阵的函数,你可以自己设定,也可以用它默认的。

method总体可以分为两类:可以加约束的,不可以加约束的。不加约束的,跟单变量基本一致,不再说明。加约束的。

  • 如果要加入bounds(变量的区间),方法必须选L-BFGS-B、TNC、SLSQP中的一种
  • 如果要加入constraint(变量的约束),方法必须选COBYLA、SLSQP、trust_constr中的一种。

所以综上来看,对于带约束的优化问题,选SLSQP是最好的。当然如果你的优化函数比较特殊,需要考虑适用性的话,就需要具体分析了。

bounds的设定比较简单,每个参数用一个(min,max),没有可以设定为None。举个例子,有这样一个优化问题:

函数设定,自变量以向量方式输入

代码语言:javascript
复制
f = lambda x:(x[0] - 1)**2 + (x[1] - 1)**2 + (x[2] - 1)**2

bound设定如下

代码语言:javascript
复制
bounds = ((0,1),(2,3),(None,None))

当然也通过constraint参数设定bound,比如x1可以理解成有两个约束:x1>=0和x1<=1。

constraint的设定相对麻烦一些,以SLSQP为例,通过字典的格式输入,分为等式约束和不等约束:

  • type参数设定为'eq'表示等式约束,设定为'ineq'表示不等式约束
  • fun参数设定约束表达式,仅输入表达式左边,默认为左边小于或等于0

对于上面的问题,输入如下

代码语言:javascript
复制
cons = {'type':'eq','fun':lambda x:[0] + x[1] + x[2],
 'type':'ineq','fun':lambda x:-2*x[1] + x[2] - 9}

优化结果如下

对于全局最优化的各种方法,函数基本和上面的一致,只是换个函数名,不再说明。

参考文档

1. https://docs.scipy.org/doc/scipy/reference/optimize.html

END

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量化小白躺平记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档