Scipy минимизация не выполняется с ограничениями или границами неравенства - PullRequest
0 голосов
/ 08 июля 2020

Я пытаюсь использовать scipy.optimize для решения проблемы минимизации, но получаю сбои при использовании ограничения неравенства или границы. Ищу любые предложения относительно правильного использования ограничений по сравнению с границами, и подойдет ли в этом случае какой-либо другой алгоритм.

Проблема:

введите описание изображения здесь

Вот воспроизводимый код:

import pandas as pd
from scipy.optimize import minimize as scimin

def obj(wc, M, wb, S):
    return (wc.dot(M.T) - wb).dot(S).dot(wc.dot(M.T) - wb)

n=278
k= 16

c_labels = ['c'+ str(i) for i in range(k)]
r_labels_1 = ['r' + str(i) +s for i in range(k) for s in ['a', 'b']]
r_labels_2 = ['r' + str(i) for i in range(k, n-k)]
r_labels = r_labels_1 + r_labels_2

wb = pd.Series(index=r_labels, data=np.random.triangular(0, 1.0/n, 0.3, n))
wb = wb/wb.sum()
cc = pd.Series(index=c_labels, data=4 + 2*np.random.random(k))
cb = pd.Series(index=r_labels, data=3 + 10*np.random.random(n))
s_pre = np.random.rand(n, n)
S = pd.DataFrame(index=r_labels, columns= r_labels, data=s_pre.dot(s_pre.T))

M = pd.DataFrame(data=np.eye(k), index= ['r'+ str(i) +'a' for i in range(k)], columns = c_labels)
for i in range(k):
    M.loc['r' + str(i)+ 'b'] = M.loc['r' + str(i) + 'a']
M = M.loc[r_labels_1].applymap(lambda x: x* np.random.rand())
M = M / M.sum()
for i in r_labels_2:
    M.loc[i] = 0

one_k = pd.DataFrame(index=M.columns, data=np.ones(len(M.columns)))
con1 = {'type': 'eq', 'fun': lambda x: x.sum() - 1}
con2 = {'type': 'eq', 'fun': lambda x: cc.dot(x) - cb.dot(wb)}

# try 1 with inequality constraint
con3 = {'type': 'ineq', 'fun': lambda x: min(x)}
consts = [con1, con2, con3]
res = scimin(obj, x0=one_k, args=(M, wb, S), constraints=consts, method='SLSQP')
wc = res['x']
oj = obj(wc, M, wb, S)

# try 2 with bounds instead of inequality constraint
bounds = [(0, 1000)] *len(M.columns)
consts = [con1, con2]
res1 = scimin(obj, x0=one_k, args=(M, wb, S), constraints=consts, bounds= bounds, method='SLSQP')
wc1 = res1['x']
oj1 = obj(wc1, M, wb, S)
...