最小化python中2个列表的线性组合的std

时间:2017-05-17 09:52:50

标签: python minimize standard-deviation

有两个相同长度的python列表(ndarrays,等等......)。

BorderThickness = 0

我想找到两个权重:w和(1-w),使v1 = [1, 2, 3] v2 = [7, 8, 9] 最小。哪个python库除了scipy.optimize.minimize?

之外

1 个答案:

答案 0 :(得分:0)

我认为这个问题有一个封闭的解决方案。我用SymPy快速尝试了,除非我做错了,给定向量a = [a_1, ..., a_k]b = [b_1, ..., b_k],解决方法是(向量是列,中间点代表矩阵乘积和 sum 是矩阵中所有元素的总和):

Solution

令人生畏。

同样,我自己并没有推断出这一点,我只是信任SymPy的输出,因此您可以使用已知解决方案查看问题的某个实例,看看它是否有效。

编辑:

关于我如何得到结果的一些背景知识。说实话,我只得到了固定大小(四)和#34;推导的#34;通式;我不知道除了手工推导之外是否还有更好的方法(afaik SymPy不处理矩阵或未定义大小的向量)。所以,无论如何,一旦你安装了SymPy,你就可以做到:

import sympy

# Derivating just for k = 4
a = sympy.Matrix(sympy.symbols('a:4'))
b = sympy.Matrix(sympy.symbols('b:4'))
w = sympy.symbols('w')
c = w * a + (1 - w) * b
mean = sum(c) / len(c)
# We minimize variance, which is equivalent to minimizing standard deviation
s2 = c - mean * sympy.Matrix([1] * len(c)) # Matrices can only be add/substract other matrices
s2 = sum(s2.multiply_elementwise(s2)) / len(s2)
# Derivate wrt w
s2dw = s2.diff(w)
# Find zero of derivative
sol = sympy.solveset(s2dw, w)
# There must be only one solution
assert len(sol) == 1
sol = list(sol).pop()
# Simplify
sol = sol.simplify()
print(sol)

>>> (-3*a0*b0 + a0*b1 + a0*b2 + a0*b3 + a1*b0 - 3*a1*b1 + a1*b2 + a1*b3 + a2*b0 + a2*b1 - 3*a2*b2 + a2*b3 + a3*b0 + a3*b1 + a3*b2 - 3*a3*b3 + 3*b0**2 - 2*b0*b1 - 2*b0*b2 - 2*b0*b3 + 3*b1**2 - 2*b1*b2 - 2*b1*b3 + 3*b2**2 - 2*b2*b3 + 3*b3**2)/(3*a0**2 - 2*a0*a1 - 2*a0*a2 - 2*a0*a3 - 6*a0*b0 + 2*a0*b1 + 2*a0*b2 + 2*a0*b3 + 3*a1**2 - 2*a1*a2 - 2*a1*a3 + 2*a1*b0 - 6*a1*b1 + 2*a1*b2 + 2*a1*b3 + 3*a2**2 - 2*a2*a3 + 2*a2*b0 + 2*a2*b1 - 6*a2*b2 + 2*a2*b3 + 3*a3**2 + 2*a3*b0 + 2*a3*b1 + 2*a3*b2 - 6*a3*b3 + 3*b0**2 - 2*b0*b1 - 2*b0*b2 - 2*b0*b3 + 3*b1**2 - 2*b1*b2 - 2*b1*b3 + 3*b2**2 - 2*b2*b3 + 3*b3**2)

您还可以检查解决方案实际上是最小的,因为当您在二阶导数中替换它时,它是一堆平方的东西(即正数):

s2dww = s2dw.diff(w)
s2dww_sol = s2dww.subs(w, sol).simplify()
print(s2dww_sol)

>>> 2*(a0 - 2*a1 + a2 - b0 + 2*b1 - b2)**2/27 + 2*(a0 + a1 - 2*a2 - b0 - b1 + 2*b2)**2/27 + 2*(2*a0 - a1 - a2 - 2*b0 + b1 + b2)**2/27