找到最适合目标向量的向量线性组合

Find linear combination of vectors that is the best fit for a target vector

我试图在多个预测中找到权重,以给出尽可能接近已知目标(例如,均方误差)的结果。

这是一个简化示例,显示了跨四个数据点的三种不同类型的预测:

target = [1.0, 1.02, 1.01, 1.04]  # all approx 1.0
forecasts = [
    [0.9, 0.91, 0.92, 0.91],  # all approx 0.9
    [1.1, 1.11, 1.13, 1.11],  # all approx 1.1
    [1.21, 1.23, 1.21, 1.23]  # all approx 1.2
]

其中一项预测始终约为 0.9,一项始终约为 1.1,一项始终约为 1.2。

我想要一种自动方法来为三个预测找到大约 [0.5, 0.5, 0.0] 的权重,因为平均前两个预测并忽略第三个非常接近目标。理想情况下,权重将被限制为非负且总和为 1。

认为我需要使用某种形式的线性规划或二次规划来做到这一点。我已经安装了 Python quadprog library,但我不确定如何将此问题转换为此类求解器所需的形式。谁能指出我正确的方向?

如果我对你的理解是正确的,你想对一些优化问题建模并解决它。如果您对一般情况感兴趣(没有任何限制),您的问题似乎非常接近常规最小二乘误差问题(例如,您可以用 scikit-learn 解决)。

我建议使用 cvxpy 库来建模优化问题。这是对凸优化问题建模的便捷方式,您可以选择要在后台运行的求解器。

通过添加您提到的约束来扩展 cvxpy least square example

# Import packages.
import cvxpy as cp
import numpy as np

# Generate data.
m = 20
n = 15
np.random.seed(1)
A = np.random.randn(m, n)
b = np.random.randn(m)

# Define and solve the CVXPY problem.
x = cp.Variable(n)
cost = cp.sum_squares(A @ x - b)
prob = cp.Problem(cp.Minimize(cost), [x>=0, cp.sum(x)==1])
prob.solve()

# Print result.
print("\nThe optimal value is", prob.value)
print("The optimal x is")
print(x.value)
print("The norm of the residual is ", cp.norm(A @ x - b, p=2).value)

在此示例中,A(矩阵)是所有向量的矩阵,x(变量)是权重,b 是已知目标。

编辑: 您的数据示例:

forecasts = np.array([
    [0.9, 0.91, 0.92, 0.91],
    [1.1, 1.11, 1.13, 1.11],
    [1.21, 1.23, 1.21, 1.23]
])

target = np.array([1.0, 1.02, 1.01, 1.04])
x = cp.Variable(forecasts.shape[0])
cost = cp.sum_squares(forecasts.T @ x - target)
prob = cp.Problem(cp.Minimize(cost), [x >= 0, cp.sum(x) == 1])
prob.solve()
print("\nThe optimal value is", prob.value)
print("The optimal x is")
print(x.value)

输出:

The optimal value is 0.0005306233766233817
The optimal x is
[ 6.52207792e-01 -1.45736370e-24  3.47792208e-01]

结果大约是 [0.65, 0, 0.34],这与您提到的 [0.5, 0.5, 0.0] 不同,但这取决于您如何定义问题。这是最小二乘误差的解决方案。

我们可以把这个问题看成一个最小二乘,确实等价于二次规划。如果我理解正确的话,你要找的权重向量是一个凸组合,所以最小二乘形式的问题是:

minimize  || [w0 w1 w2] * forecasts - target ||^2
    s.t.  w0 >= 0, w1 >= 0, w2 >= 0
          w0 + w1 + w2 == 1

qpsolvers 包中有一个开箱即用的最小二乘函数:

import numpy as np
from qpsolvers import solve_ls

target = np.array(target)
forecasts = np.array(forecasts)
w = solve_ls(forecasts.T, target, G=-np.eye(3), h=np.zeros(3), A=np.array([1, 1., 1]), b=np.array([1.]))

您可以在documentation中查看矩阵G、h、A和b对应于上述问题。使用 quadprog 作为后端求解器,我在我的机器上得到以下解决方案:

In [6]: w
Out[6]: array([6.52207792e-01, 9.94041282e-15, 3.47792208e-01])

In [7]: np.dot(w, forecasts)
Out[7]: array([1.00781558, 1.02129351, 1.02085974, 1.02129351])

这与 Roim 的回答中的解决方案相同。 (CVXPY 确实是一个很好的开始方式!)