我有四个数组a1、a2、a3、a4,每个数组的长度都是500。我有一个目标数组at,长度也是500。这些数组分别表示图形上不均匀分布的点的y坐标。我在一个单独的数组中有x坐标。
我想优化系数c1,c2,c3,c4,使c1x1+ c2x2 + c3x3 + c4x4和at之间的面积差最小化。系数之和必须为1,并且在0和1之间。
我目前使用scipy.optimize.minimize来执行此操作。(数组[c1,c2,c3,c4])求和为1。损失函数将目标变量乘以数组a1,a2,a3,a4,然后找到此和与at之间的绝对差。此绝对差在每对连续的x坐标之间积分,并且输出这些积分的和。
代码如下:
xpoint_diffs = xpoints[1:] - xpoints[:-1]
a1a2a3a4 = np.array([a1,a2,a3,a4])
def lossfunc(x):
abs_diff = abs(at - (a1a2a3a4 * x).sum(axis = 1))
return ((absdiff[:-1] + absdiff[1:])/2 * xpoint_diffs).sum()
有没有更快的方法?
然后将约束和损失函数传递到scipy.optimize.minimize中。
1条答案
按热度按时间zc0qhyus1#
这不是一个完整的解决方案,更像是一些可能导致一个解决方案的想法。另外,有人请再次检查我的数学。
变量和测试数据
首先,让我们从定义一些测试数据开始。在这样做的时候,我转置了
a1a2a3a4
矩阵,因为它会证明更方便。另外,我将它重命名为a14
,因为我不想一直写整个东西,对不起。目标
好吧,这是我第一个有点困惑的地方:OP将目标描述为两个图形之间的“面积差”。X坐标由
xpoints
给出。目标的Y坐标由at
给出,并且我们搜索coeffs
,使得a14 @ coeffs
给出接近目标的Y坐标。现在,当我们谈论“图下的面积”时,我的第一直觉是分段线性的。类似于trapezoidal rule,这给了我们公式
sum{(y[i+1]+y[i]) * (x[i+1]-x[i])} / 2
。我们可以稍微重新公式化,得到(y[0]*(x[1]-x[0]) + y[1]*(x[2]-x[0]) + y[2]*(x[3]-x[1]) + ... + y[n-1]*(x[n-1]-x[n-2])) / 2
的形式。我们想预先计算x
的差值和缩放因子。这些因子与OP使用的不同。我猜它们是对分段常数函数而不是分段线性函数进行积分?无论如何,在这两者之间切换应该足够简单,所以我将其作为替代方案留在这里。
功能丧失
根据我的解释调整OP的损失函数,得到
正如我在注解中提到的,这可以通过使用矩阵向量乘法来简化。
这与
abs((a14 * weights[:, np.newaxis]) @ coeffs - (at * weights)).sum()
是一样的,这反过来又使我们很明显地讨论的是最小化L1范数。就损失函数的计算而言,这并不是一个巨大的进步,但是,它对把我们的问题变成一个规则的模式有很大的帮助。
近似解
正如在评论中所指出的,L1范数下的
abs()
函数是优化的毒药,因为它是不可微的。如果我们切换到L2范数,我们基本上有一个带有附加约束的最小二乘拟合。当然,这有点不合理,因为我们开始解决一个不同的,如果密切相关的问题。我怀疑解决方案将是“足够好的”;或者它可以是起始溶液,然后将其抛光以符合实际目标。在任何情况下,我们都可以使用
scipy.optimize.lsq_linear
作为一个快速简单的求解器,但是它不支持线性约束,我们可以用正则化参数来模拟它。