2016-12-25 163 views
0

我很苦惱以下設置。約束線性優化設置

我的數據如下:

Group ID Wt  Coeff  Coeff*Wt 
------ --- ------ ------- ------- 
Group1 A 10.00% 1.00000  0.100 
Group1 B 10.00% 1.00000  0.100 
Group1 C 10.00% 3.00005  0.300 
Group2 D 10.00% 1.00000  0.100 
Group2 E 10.00% 1.00000  0.100 
Group2 F 10.00% 1.00000  0.100 
Group2 G 10.00% 7.80016  0.780 
Group3 H 10.00% 7.80485  0.780 
Group3 I 10.00% 1.00000  0.100 
Group3 J 10.00% 0.39529  0.040 



Objective function: Fmin = mimimize(sum of weights * coeff) 

我需要實現以下限制:

Sum of Weights*Coeff of Group1 = 20% of total minimized fmin 
Sum of Weights*Coeff of Group1 = 45% of total minimized fmin 
Sum of Weights*Coeff of Group1 = 35% of total minimized fmin 

而下面的邊界條件:

Weights <=10% and Weights > 0.30% 

而且

Sum of weights = 100% 

我想用下面的代碼來實現這一點。

我不知道爲什麼這不工作:

from scipy.optimize import linprog 

c = [ 1.0000 ,1.0000 ,3.0001 ,1.0000 ,1.0000 ,1.0000 ,7.8002 ,7.8049 ,1.0000 ,0.3953 ] 

groupPerID = ['Group1','Group1','Group1','Group2','Group2','Group2','Group2','Group3','Group3','Group3'] 

groupList = ['Group1','Group2','Group3'] 

groupUpperBound = [0.20,0.45,0.40] 

A_eq_list = [] 
A_eq_list.append([1]*len(c)) 

b_eq_list = [1] 

for idx,currentGroup in enumerate(groupList): 

    matches = [i for i in range(len(groupPerID)) if groupPerID[i] == currentGroup] 

    currentGroupUB = groupUpperBound[idx] 

    x_list = [float(-1*currentGroupUB*coeff) for coeff in c] 

    for idx in matches: 
     x_list[idx] = float((1-currentGroupUB)*c[idx]) 

    A_eq_list.append(x_list) 

b_eq_list.extend([0]*len(groupUpperBound)) 
res = linprog(c, A_eq=A_eq_list, b_eq=b_eq_list,bounds =(0.003,0.1),options={'tol':0.05}) 
print(res) 

可有人請指出我在做什麼錯誤?

+0

如果我理解正確,您正嘗試優化要分配的權重,對嗎?所以你的數據每重量10%只是一個例子? – tBuLi

+0

是的,這是正確的。該解決方案在Excel解算器中進行了優化。我想將excel解算器約束轉換爲python linprog。 – DrBug

+0

'[0.20,0.45,0,40]'中有一個逗號,而不是一個點。但一般來說,我要做的是打印A_eq和b_eq,並考慮它們與你期望的不同之處。 – FTP

回答

1

所以我在我的scipy包裝symfit中實施它,它負責處理所有的鍋爐板代碼。它現在起作用,除了我還沒有實現權重的限制。然而,我認爲那些在你的問題中是錯誤的,因爲滿足所有權重總和爲1的限制的唯一方法是將它們全部設置爲0.1的上限。除此之外,這裏是我的嘗試:

from symfit import parameters, Minimize, Variable, Eq 
import numpy as np 

# Make 10 weight parameters w_i to optimize 
weights = parameters(','.join('w_{}'.format(i) for i in range(1, 11))) 
c = np.array([1.0000, 1.0000, 3.0001, 1.0000, 1.0000, 1.0000, 7.8002, 7.8049, 1.0000, 0.3953]) 
f = Variable() 

for w_i in weights: 
    w_i.min = 0.003 
    w_i.max = 1.0 
    w_i.value = 0.1 

sum_of_group_1 = sum(c_i * w_i for c_i, w_i in zip(c, weights)[0:3]) 
sum_of_group_2 = sum(c_i * w_i for c_i, w_i in zip(c, weights)[3:7]) 
sum_of_group_3 = sum(c_i * w_i for c_i, w_i in zip(c, weights)[7:10]) 
# Function to minimize 
model = {f: sum_of_group_1 + sum_of_group_2 + sum_of_group_3} 

constraints = [ 
    Eq(0.20 * sum_of_group_1, 0.45 * sum_of_group_2), 
    Eq(0.20 * sum_of_group_1, 0.35 * sum_of_group_3), 
    Eq(sum(weights), 1) 
] 

fit = Minimize(model, constraints=constraints) 
fit.eval_jacobian = None # Workaround needed because f is just a scalar, not an array 
fit_result = fit.execute() 

print(fit_result) 
print(sum(fit_result.value(w) for w in weights)) # >>> 1.0 

您可以在文檔here閱讀更多。

+0

感謝tBuli。我現在正在努力檢查我試圖解決的優化問題是否可行。我會回來並更新我的發現,並接受你的幫助作爲最終答案。 – DrBug

+0

很高興能幫到你!是的,如果沒有深入研究,我會認爲這個系統是不確定的,因此這些解決方案不是唯一的,如果有的話。祝你好運! – tBuLi