@1007477689
2020-04-04T13:23:52.000000Z
字数 2199
阅读 664
量化
优化问题是量化中经常会碰到的,之前写的风险平价/均值方差模型最终都需要解带约束的最优化问题,本文总结用 python 做最优化的若干函数用法。
首先说明,本文仅把 python 看作一种工具,说明如何用 python 求解优化问题,不过多考虑由于模型方法导致的精度、速度、适用性等问题,具体问题还需要具体分析,选择适当的方法,或者自己手写。
python 中最常用的做最优化的模块是 scipy.optimize
,这里只说明这一模块的使用,其他的略过。
根据官方文档的说明,scipy.optimze
的功能涉及5方面:
1,4中得到的是“给定区间内的局部最优解”,2中得到的是“全局最优解”,每个函数下有若干方法可以选择。当然求解一元的优化问题也可以用 .minimize()
,但尝试过之后发现用 .minimize_scalar()
的速度要更快一些,下面具体说明
用 .minimize_scalar()
解一元优化。一元优化问题可以表述如下
是优化目标, 是自变量的取值范围,也可以没有或只有上界或下界, 是自变量可能有的其他约束。如果有 约束,不能用 .minimize_scalar()
,只能用 .minimize()
。
.minimize_scalar()
的具体用法如下:
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
:自变量区间,对应上面的 和 ,只在 method = 'bounded'
时有效
tol
, options
:设定优化的参数,最小误差、最大迭代次数、是否返回每步的结果等。
args
:优化函数的其他输入参数
只需要注意,如果自变量 没有区间设定,直接用默认的就可以了,如果 有区间约束,必须用 "bounded" 方法。
返回值的 fun
是最优函数值,x是最优自变量,可以看出,method取brent时,设定区间没什么用。
多元优化问题的表述跟一元基本一致,把 理解成向量就可以了,求解这一类问题也可以用 .minimize()
函数。
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
。举个例子,有这样一个优化问题:
函数设定,自变量以向量方式输入
f = lambda x: (x[0] - 1)**2 + (x[1] - 1)**2 + (x[2] - 1)**2
bound设定如下
bounds = ((0,1), (2,3), (None,None))
当然也通过constraint参数设定bound,比如x1可以理解成有两个约束:x1>=0和x1<=1。
constraint的设定相对麻烦一些,以SLSQP为例,通过字典的格式输入,分为等式约束和不等约束:
type参数设定为'eq'表示等式约束,设定为'ineq'表示不等式约束
fun参数设定约束表达式,仅输入表达式左边,默认为左边小于或等于0
对于上面的问题,输入如下
cons = {'type':'eq','fun':lambda x:[0] + x[1] + x[2],
'type':'ineq','fun':lambda x:-2*x[1] + x[2] - 9}
优化结果如下
对于全局最优化的各种方法,函数基本和上面的一致,只是换个函数名,不再说明。
参考文档