2015-10-28 5 views
5

Mam następujący kod do rozwiązania nieujemnego najmniejszego kwadratu. Korzystanie scipy.nnls.Jak zawrzeć ograniczenie do rozwiązania funkcji Scipy NNLS, tak aby miało ono wartość 1

import numpy as np 
from scipy.optimize import nnls 

A = np.array([[60, 90, 120], 
       [30, 120, 90]]) 

b = np.array([67.5, 60]) 

x, rnorm = nnls(A,b) 

print x 
#[ 0.   0.17857143 0.42857143] 
# Now need to have this array sum to 1. 

Co chcę zrobić, to zastosować ograniczenie na x roztworu tak, że sumy go do 1. W jaki sposób można to zrobić?

Odpowiedz

6

Nie sądzę, że można użyć nnls bezpośrednio jako Fortran code to wywołania nie pozwalają na dodatkowe ograniczenia. Jednakże ograniczeniem, że środki równanie można wprowadzać jako trzeciego równania więc przykładowy system ma postać,

60 x1 + 90 x2 + 120 x3 = 67.5 
30 x1 + 120 x2 + 90 x3 = 60 
    x1 +  x2 +  x3 = 1 

Jak to jest układ równań liniowych, dokładne rozwiązanie może być uzyskane od x=np.dot(np.linalg.inv(A),b), dzięki czemu x=[0.6875, 0.3750, -0.0625]. Wymaga to, aby było ujemne. Dlatego nie ma dokładnego rozwiązania, gdy x jest pozytywny dla tego problemu.

wynoszący około rozwiązania, w którym x jest ograniczony jest pozytywny, to można uzyskać stosując

import numpy as np 
from scipy.optimize import nnls 

#Define minimisation function 
def fn(x, A, b): 
    return np.sum(A*x,1) - b 

#Define problem 
A = np.array([[60., 90., 120.], 
       [30., 120., 90.], 
       [1., 1., 1. ]]) 

b = np.array([67.5, 60., 1.]) 

x, rnorm = nnls(A,b) 

print(x,x.sum(),fn(x,A,b)) 

, zawierające x=[0.60003332, 0.34998889, 0.] z x.sum()=0.95.

Myślę, że jeśli chciał bardziej ogólne rozwiązanie w tym ograniczeń Podsumowując, trzeba by użyć minimalizacji z ograniczeniami/wyraźnych granic w następującej formie,

import numpy as np 
from scipy.optimize import minimize 
from scipy.optimize import nnls 

#Define problem 
A = np.array([[60, 90, 120], 
       [30, 120, 90]]) 

b = np.array([67.5, 60]) 

#Use nnls to get initial guess 
x0, rnorm = nnls(A,b) 

#Define minimisation function 
def fn(x, A, b): 
    return np.linalg.norm(A.dot(x) - b) 

#Define constraints and bounds 
cons = {'type': 'eq', 'fun': lambda x: np.sum(x)-1} 
bounds = [[0., None],[0., None],[0., None]] 

#Call minimisation subject to these values 
minout = minimize(fn, x0, args=(A, b), method='SLSQP',bounds=bounds,constraints=cons) 
x = minout.x 

print(x,x.sum(),fn(x,A,b)) 

co daje x=[0.674999366, 0.325000634, 0.] i x.sum()=1. Od minimalizacji suma jest poprawna, ale wartość x nie jest całkiem odpowiednia z np.dot(A,x)=[ 69.75001902, 59.25005706].

+0

W twoim pierwszym bloku kodu 'print (x, x.sum(), fn (x, A, b))' skąd pochodzi 'fn'? – neversaint

+1

Niestety, powinno być fn z drugiego przykładu (Ax-b). Poprawiłem. –

+0

Dzięki. Staram się spojrzeć na moje inne powiązane [pytanie] (http://stackoverflow.com/questions/33404908/best-way-to-scale-the-matrix-variables-in-scipy-linear-programming-scheme)? – neversaint

Powiązane problemy