(十二)用SciPy模块求解最优化问题

运用子模块optimize中的minimize函数

1、第一步,定义需要求解的函数(求最大值加负号);
2、第二步,以字典格式输入约束条件(等式或不等式),以元组形式输入要求变量的边界值;
3、第三步,optimize.minimize(fun,x0,method,bounds,constraints),fun是第一步定义的函数;x0是猜测解,列表或元组形式;method一般填’SLSQP’(序贯最小二乘规划);bounds和constraints在第二步中。

示例一

求函数 f(x,y,z)=x + 2y+ 3z +1在附加条件xyz = 12(其中x, y, z >0 )下的极小值。

import numpy as np
from scipy import optimize
a=1e-20#非常接近0的值代替0,因为题目要求x、y、z不能等于0
fun=lambda x:x[0]+2*x[1]+3*x[2]+1#极值函数,多个参数用x的切片形式代替
cons=({'type': 'eq', 'fun': lambda x: x[0]*x[1]*x[2]-12}, 
        {'type': 'ineq', 'fun': lambda x: x[0]-a}, 
        {'type': 'ineq', 'fun': lambda x: x[1]-a},
        {'type': 'ineq', 'fun': lambda x: x[2]-a})
        #等式约束条件xyz=1与三个参数大于零的不等式约束条件
res=optimize.minimize(fun,(1.0, 1.0, 1.0), method='SLSQP', constraints=cons)
res
Out[5]: 
     fun: 13.480502824727887
     jac: array([1., 2., 3.])
 message: 'Optimization terminated successfully.'
    nfev: 72
     nit: 14
    njev: 14
  status: 0
 success: True
       x: array([4.16022894, 2.08007638, 1.38670704])

或者仅写等式约束条件,在下限参数写0,上限写一个很大的数也能得到同样的结果:

cons=({'type': 'eq', 'fun': lambda x: x[0]*x[1]*x[2]-12})#等式约束条件xyz=1
res=optimize.minimize(fun,(1.0, 1.0, 1.0), method='SLSQP', bounds=((0,1e+10),(0,1e+10),(0,1e+10)),constraints=cons)

示例二

现有3支股票的收盘价P、收益率R和贝塔值数据b,资金一千万,在不允许卖空的情况下,希望投资组合收益率最大且组合贝塔<1.2,求每支股票的权重。

P=np.array([5.29,26.67,6.50])
R=np.array([0.155143,0.132796,0.055905])
b=np.array([1.41,1.21,1.06])
def f(w):#定义求最优值函数
	w=np.array(w)
	return -np.dot(R,w)#写np.sum(R*w)也可
cons=({'type':'eq','fun':lambda w:np.sum(w)-1},{'type':'ineq','fun':lambda w:1.2-np.dot(w,b)})
#等式约束:∑wi-1=0;不等式约束:1.2-∑wi*b≥0
bnds=((0,1),(0,1),(0,1))#每支股票权重的边界条件
result=optimize.minimize(f,[0.5,0.25,0.25],method='SLSQP',bounds=bnds,constraints=cons)
result
Out[1]: 
     fun: -0.1276699349815123
     jac: array([-0.155143, -0.132796, -0.055905])
 message: 'Optimization terminated successfully.'
    nfev: 25
     nit: 5
    njev: 5
  status: 0
 success: True
       x: array([1.11022302e-16, 9.33333355e-01, 6.66666452e-02])

计算三支股票的权重和投资组合收益率:

result.x.round(2)
Out[6]: array([0.  , 0.93, 0.07])
-result.fun
Out[7]:0.1276699349815123

购买每支股票的数量(整数):

stock=['股票a','股票b','股票c']
for i in range(3):
	print(stock[i],(10000000/P[i]*result.x[i]).round(0))

股票a 0.0
股票b 349956.0
股票c 102564.0

因此股票a买0手,股票b买3500手,股票c买1026手,能达到最高组合收益率12.77%左右。

发布了31 篇原创文章 · 获赞 2 · 访问量 1611

猜你喜欢

转载自blog.csdn.net/hzk427/article/details/104045268
今日推荐