我在形式上设定了等式:Y = aA + bB 其中Y-知道浮点数的向量(只有这一个是已知的!); a,b是未知的标量(浮点数),A,B是浮点数的未知向量。每个方程都有自己的Y,a,b,而所有方程共享相同的未知向量A和B.
我有这样的等式,所以我的问题是最小化功能: (Y-AA-BB)+(Y'-A'A-B'B)+ .... 我还有许多类型的不等式约束:Ai> Aj(矢量A的第i个元素),Bi> = Bk,Bi> 0,a> a',......
是否有可以处理此问题的软件或库(最好是python)?
答案 0 :(得分:3)
这是线性问题(至少在线性最小二乘意义上,继续阅读)!
它也没有完全明确指出,因为不清楚在你的情况下是否应该总是有一个可行的解决方案,或者你是否想要最小化一些给定的损失。你的文字听起来像后者,但在这种情况下,必须选择损失(这对可能的算法有所不同)。让我们采取欧几里德规范(可能是这里最好的选择)!
暂时忽略约束,我们可以将此问题视为线性矩阵方程问题的基本最小二乘解(欧几里得范数与平方欧几里德范数没有区别!)
min || b - Ax ||^2
下面:
M = number of Y's
N = size of Y
b = (Y0,
Y1,
...) -> shape: M*N (flattened: Y_x = (y_x_0, y_x_1).T)
A = ((a0, 0, 0, ..., b0, 0, 0, ...),
(0, a0, 0, ..., 0, b0, 0, ...),
(0, 0, a0, ..., 0, 0, b0, ...),
...
(a1, 0, 0, ..., b1, 0, 0, ...)) -> shape: (M*N, N*2)
x = (A0, A1, A2, ... B0, B1, B2, ...) -> shape: N*2 (one for A, one for B)
此代码:
代码:
import numpy as np
from scipy.optimize import minimize
np.random.seed(1)
""" Fake-problem (usually the job of the question-author!) """
def get_partial(N=10):
Y = np.random.uniform(size=N)
a, b = np.random.uniform(size=2)
return Y, a, b
""" Optimization """
def optimize(list_partials, N, M):
""" General approach:
This is a linear system of equations (with constraints)
Basic (unconstrained) form: min || b - Ax ||^2
"""
Y_all = np.vstack(map(lambda x: x[0], list_partials)).ravel() # flat 1d
a_all = np.hstack(map(lambda x: np.repeat(x[1], N), list_partials)) # repeat to be of same shape
b_all = np.hstack(map(lambda x: np.repeat(x[2], N), list_partials)) # """
def func(x):
A = x[:N]
B = x[N:]
return np.linalg.norm(Y_all - a_all * np.repeat(A, M) - b_all * np.repeat(B, M))
""" Example constraints: A >= B element-wise """
cons = ({'type': 'ineq',
'fun' : lambda x: x[:N] - x[N:]})
res = minimize(func, np.zeros(N*2), constraints=cons, method='SLSQP', options={'disp': True})
print(res)
print(Y_all - a_all * np.repeat(res.x[:N], M) - b_all * np.repeat(res.x[N:], M))
""" Test """
M = 4
N = 3
list_partials = [get_partial(N) for i in range(M)]
optimize(list_partials, N, M)
输出:
Optimization terminated successfully. (Exit mode 0)
Current function value: 0.9019356096498999
Iterations: 12
Function evaluations: 96
Gradient evaluations: 12
fun: 0.9019356096498999
jac: array([ 1.03786588e-04, 4.84041870e-04, 2.08129734e-01,
1.57609582e-04, 2.87599862e-04, -2.07959406e-01])
message: 'Optimization terminated successfully.'
nfev: 96
nit: 12
njev: 12
status: 0
success: True
x: array([ 1.82177105, 0.62803449, 0.63815278, -1.16960281, 0.03147683,
0.63815278])
[ 3.78873785e-02 3.41189867e-01 -3.79020251e-01 -2.79338679e-04
-7.98836875e-02 7.94168282e-02 -1.33155595e-01 1.32869391e-01
-3.73398306e-01 4.54460178e-01 2.01297470e-01 3.42682496e-01]
我没有检查结果!如果有错误,那就是实现错误,而不是概念错误(我的意见)!
答案 1 :(得分:0)
我同意sascha这是一个线性问题。因为我不太喜欢约束,所以我更倾向于使它成为非线性而没有约束。我这样做是通过设置这样的向量A=(a1**2, a1**2+a2**2, a1**2+a2**2+a3**2, ...)
来确保它是全部为正A_i > A_j
为i>j
。这使得错误有点问题,因为您现在必须考虑错误传播以获得A1
,A2
等,包括相关性,但最后我会对此有一个重要的观点。 "简单"解决方案如下:
import numpy as np
from scipy.optimize import leastsq
from random import random
np.set_printoptions(linewidth=190)
def generate_random_vector(n, sortIt=True):
out=np.fromiter( (random() for x in range(n) ),np.float)
if sortIt:
out.sort()
return out
def residuals(parameters,dataVec,dataLength,vecDims):
aParams=parameters[:dataLength]
bParams=parameters[dataLength:2*dataLength]
AParams=parameters[-2*vecDims:-vecDims]
BParams=parameters[-vecDims:]
YList=dataVec
AVec=[a**2 for a in AParams]##assures A_i > 0
BVec=[b**2 for b in BParams]
AAVec=np.cumsum(AVec)##assures A_i>A_j for i>j
BBVec=np.cumsum(BVec)
dist=[ np.array(Y)-a*np.array(AAVec)-b*np.array(BBVec) for Y,a,b in zip(YList,aParams,bParams) ]
dist=np.ravel(dist)
return dist
if __name__=="__main__":
aList=generate_random_vector(20, sortIt=False)
bList=generate_random_vector(20, sortIt=False)
AVec=generate_random_vector(5)
BVec=generate_random_vector(5)
YList=[a*AVec+b*BVec for a,b in zip(aList,bList)]
aGuess=20*[.2]
bGuess=20*[.3]
AGuess=5*[.4]
BGuess=5*[.5]
bestFitValues, covMX, infoDict, messages ,ier = leastsq(residuals, aGuess+bGuess+AGuess+BGuess ,args=(YList,20,5) ,full_output=True)
print "a"
print aList
besta = bestFitValues[:20]
print besta
print "b"
print bList
bestb = bestFitValues[20:40]
print bestb
print "A"
print AVec
bestA = bestFitValues[-2*5:-5]
realBestA = np.cumsum([x**2 for x in bestA])
print realBestA
print "B"
print BVec
bestB = bestFitValues[-5:]
realBestB = np.cumsum([x**2 for x in bestB])
print realBestB
print covMX
错误和相关性问题是问题的解决方案不是唯一的。如果Y = a A + b B
是一个解决方案,我们,例如,旋转,A = c E + s F
和B = -s E + c F
,那么Y = (ac-bs) E + (as+bc) F =e E + f F
也是一个解决方案。因此,参数空间完全平坦于解决方案"导致巨大的错误和世界末日的相关性。