jcrick
jcrick

Reputation: 33

Weights minimization issue with linprog

I am trying to use python (and at present failing) to come to a more efficient solution than Excel Solver provides for an optimization problem.

Matrices

The problem is the form AB=C -->D Where AB produces C where the absolute value for C-D for each row in the matrix is minimized.

I have seven funds contained in matrix B all of which have geographic exposure of the form

FUND_NAME = np.array([UK,USA,EuroZone, Japan,EM,Apac)]

as below


RLS = np.array([0.788743177, 0.168048481,0,0.043208342,0,0])
LIOGLB=np.array([0.084313978,0.578528092,0,0.23641746,0.033709666,0.067030804])
LIONEUR=np.array([0.055032339,0,0,0.944967661,0,0])
STEW_WLDWD=np.array([0.09865472,0.210582713,0.053858632,0.431968002,0.086387178,0.118548755])
EMMK=np.array([0.080150377,0.025212864,0.597285513,0.031832241,0.212440426,0.053078578])
PAC=np.array([0,0.013177633,0.41273195,0,0.510644775,0.063445642])
PICTET=np.array([0.089520913,0.635857603,0,0.218148413,0.023290413,0.033182659])

From this I need to construct an optimal weighting of the seven funds using a matrix (imaginatively named A) [x1,x2,x3,x4,x5,x6,x7] with x1+x2+...+x7=1 & Also for i=(1,7) xi lower bound =0 xi upper bound =0.25

To arrive at the actual regional weights (matrix C)as close as possible to the below Target array (which corresponds to matrix D above)

Target=np.array([0.2310,0.2576,0.1047,0.1832,0.1103,0.1131])

I've tried using libprog. But I know that the answer I am getting is wrong.

Funds =np.array([RLS,LIOGLB,    LIONEUR,STEW_WLDWD, EMMK,PAC,PICTET])
twentyfive=np.full((1, 7), 0.25)
bounds=[0,0.25]

res = linprog(Target,A_ub=Funds,b_ub=twentyfive,bounds=[bounds])

Can anyone help me move on from excel ?

Upvotes: 0

Views: 300

Answers (1)

Erwin Kalvelagen
Erwin Kalvelagen

Reputation: 16724

This is really a LAD regression problem (LAD=Least Absolute Deviation) with some side constraints. Different LP formulations for the LAD regression problems can be found here. Based on the sparse bounding problem, we can formulate the LP model:

enter image description here

This is the mathematical model I am going to try to solve with linprog. The coloring as as follows: blue symbols represent data, red symbols are the decision variables. x are the allocations (fractions) we need to find, d are the residuals of the linear fit and r are the absolute values of d.

linprog requires an explicit LP matrix. For the model above, this A matrix can look like:

enter image description here

With this it is no longer very difficult to develop a Python implementation. The Python code can look like:

import numpy as np
import scipy.optimize as sp

B = np.array([[0.788743177, 0.168048481,0,0.043208342,0,0],
            [0.084313978,0.578528092,0,0.23641746,0.033709666,0.067030804],
            [0.055032339,0,0,0.944967661,0,0],
            [0.09865472,0.210582713,0.053858632,0.431968002,0.086387178,0.118548755],
            [0.080150377,0.025212864,0.597285513,0.031832241,0.212440426,0.053078578],
            [0,0.013177633,0.41273195,0,0.510644775,0.063445642],
            [0.089520913,0.635857603,0,0.218148413,0.023290413,0.033182659]]).T

target = np.array([0.2310,0.2576,0.1047,0.1832,0.1103,0.1131])

m,n = np.shape(B)

A_eq = np.block([[B,          np.eye(m),  np.zeros((m,m))],
                [np.ones(n), np.zeros(m), np.zeros(m)]])
A_ub = np.block([[np.zeros((m,n)),-np.eye(m), -np.eye(m)],
                 [np.zeros((m,n)),np.eye(m), -np.eye(m)]])

b_eq = np.block([target,1])
b_ub = np.zeros(2*m)

c = np.block([np.zeros(n),np.zeros(m),np.ones(m)])

bnd =   n*[(0,0.25)] + m*[(None,None)] + m*[(0,None)]

res = sp.linprog(c,A_ub,b_ub,A_eq,b_eq,bnd,options={'disp':True})

allocation = res.x[0:n] 

The results look like:

Primal Feasibility  Dual Feasibility    Duality Gap         Step             Path Parameter      Objective          
1.0                 1.0                 1.0                 -                1.0                 6.0                 
0.3777262386888     0.3777262386888     0.3777262386888     0.6478228594143  0.3777262386888     0.3200496644143     
0.08438152300367    0.08438152300366    0.08438152300367    0.8087424108466  0.08438152300366    0.1335722585582     
0.01563291142478    0.01563291142478    0.01563291142478    0.8341722620104  0.01563291142478    0.1118298108651     
0.004083901923022   0.004083901923022   0.004083901923023   0.7432737130498  0.004083901923024   0.1049630948572     
0.0006190254179117  0.0006190254179117  0.0006190254179116  0.8815177164943  0.000619025417913   0.1016021916581     
3.504935403199e-05  3.504935403066e-05  3.504935403079e-05  0.9676694788778  3.504935402756e-05  0.1012177893279     
5.983549975387e-07  5.98354980932e-07   5.983549810074e-07  0.9885372873161  5.983549719474e-07  0.1011921413019     
3.056236812029e-11  3.056401712736e-11  3.056394819773e-11  0.9999489201822  3.056087926755e-11  0.1011915586046     
Optimization terminated successfully.
         Current function value: 0.101192    
         Iterations: 8

print(allocation)

[2.31621461e-01 2.50000000e-01 9.07425872e-12 2.50000000e-01
 4.45030949e-10 2.39692743e-01 2.86857955e-02]

Upvotes: 2

Related Questions