确定比率以达到3个值的平均值

时间:2015-04-16 20:27:41

标签: algorithm math

我有常数A,B,C和N,我想弄清楚如何“混合”A,B和C的数量来创建N的平均值。

在公式中,它看起来像这样:

(xA + yB + zC)/(x+y+z) = N

如何计算x,y,z的值?

编辑:我不是在寻找有限的解决方案,我正在寻找一种最合适的算法,它将返回x,y和z之和的最低值。

2 个答案:

答案 0 :(得分:2)

我认为你的问题很合理。处理此类问题的一种方法是查找最小长度的解(p1,p2,p3)。这样做有一个明确的程序,它给出了明确的单一结果。假设我们的系统是

|A B C| |p1|   |N|
|1 1 1| |p2| = |1|
        |p3| 

其中p1, p2, p3是混合物中A, B, C的三个权重。我们可以将这三个矩阵命名如下

    |A B C|      |p1|      |N|
M = |1 1 1|, x = |p2|, y = |1|
                 |p3|

然后我们构造M的伪逆并求解如下公式:

x = M^T (M M^T)^{-1} y

向量x然后解决系统,并且是最小长度的向量。上面的等式可以通过拉格朗日乘数的计算得到,但你不需要知道使用它。

在你的情况下,我手工完成了计算而没有太大困难,并获得了解决方案

p1 = ( (3*A-S)*N - A*S+T ) / ( (A-B)^2 + (B-C)^2 + (C-A)^2 )
p2 = ( (3*B-S)*N - B*S+T ) / ( (A-B)^2 + (B-C)^2 + (C-A)^2 )
p3 = ( (3*C-S)*N - C*S+T ) / ( (A-B)^2 + (B-C)^2 + (C-A)^2 )

其中S=A+B+CT=A^2+B^2+C^2。您可以检查它是否满足您的问题的所有要求,并且您可以与其他解决方案进行比较,以了解我的解决方案是最小的。请参阅下面的Java实现,它在命令行中使用A,B,C和N,并将最佳混合的权重打印为百分比。请注意,在极端情况附近(当N接近min(A,B,C)max(A,B,C)时),伪逆方法会给出负权重。在这种情况下,您应将相应的权重设置为0,并使用标准线性代数技术计算其他两个变量。如果N超出min(A,B,C)max(A,B,C)的间隔,则无法获得非负混合,因此实现会打印出具有负权重的答案。

一般来说,如果你有一个矩阵库,计算是快速而直接的。有关更多信息,请搜索伪逆或伪逆。

public class Mixture {
  public static void main(String[] args) {
    // calculate an optimal mixture of A, B, C to make N
    double A = Double.parseDouble(args[0]);
    double B = Double.parseDouble(args[1]);
    double C = Double.parseDouble(args[2]);
    double N = Double.parseDouble(args[3]);

    // these formulas were derived from calculations of the pseudo-inverse
    // of the matrix {{A,B,C},{1,1,1}}
    double S = A + B + C;
    double T = A*A + B*B + C*C;
    double D = (A-B)*(A-B) + (B-C)*(B-C) + (C-A)*(C-A);

    double p1 = ( (3*A-S)*N + (-A*S+T)) / D;
    double p2 = ( (3*B-S)*N + (-B*S+T)) / D;
    double p3 = ( (3*C-S)*N + (-C*S+T)) / D;

    // if pseudo-inverse calculation gives a negative weight, set weight to 0
    // and calculate exact solution
    if (p1<0) { p1 = 0; p2 = (N-C)/(B-C); p3 = (B-N)/(B-C); }
    if (p2<0) { p2 = 0; p1 = (N-C)/(A-C); p3 = (A-N)/(A-C); }
    if (p3<0) { p3 = 0; p1 = (N-B)/(A-B); p2 = (A-N)/(A-B); }

    p1 = Math.round(p1*1000)/10.0;
    p2 = Math.round(p2*1000)/10.0;
    p3 = Math.round(p3*1000)/10.0;

    System.out.println("Mixture weights: " + p1 + "%, " + p2 + "%, " + p3 + "%");
    System.out.println("Check p1*A+p2*B+p3*C = " + ((p1*A+p2*B+p3*C)/100));
    System.out.println("Check p1 + p2 + p3 = " + (p1+p2+p3) + "%");
  }
}

答案 1 :(得分:1)

你不能。实数中的无限三元组{x,y,z}可以解决您的问题。即使您要求{x,y,z}为正整数,也可能存在多个解。要看到这一点,请将您的问题想象为试图解决此问题:找到p1,p2和p3这样

A p1 + B p2 + C p3 = N

,其中

p1 = x/(x+y+z)
p2 = y/(x+y+z)
p3 = z/(x+y+z)

你有2个方程,A p1 + B p2 + C p3 = N和p1 + p2 + p3 = 1,有3个未知数{p1,p2,p3},所以有无数个解。

根据以下评论中的讨论,即使没有独特的解决方案,也可以找到 a 解决方案。就像这样,用伪代码:

gotp3 = false
while !gotp3 {
    gotp2 = false
    while !gotp2 {
        p1 = random number in the range [0,1]
        p2 = ( (N-C) - (A-C)*p1 ) / (B-C)
        gotp2 = (p2 >= 0 && p2 <= 1)
    }
    p3 = 1 - p1 - p2
    gotp3 = (p3 >= 0 && p3 <= 1)
}
s = random number in any interval you want // s = x+y+z
x = p1 * s
y = p2 * s
z = p3 * s

请注意,当B = C时会出现问题,但我会根据我已经写过的内容找出解决方法。

最后一件事。注意,如果N> (A + B + C)则没有解决方案,因为一组数字的平均值必须始终小于这些数字的总和。您可能也希望在顶部进行测试。

在@ EdwardDoolittle的回答中添加了注释

虽然我在技术上是正确的,但是有无数的解决方案,但@EdwardDoolittle是正确的,因为当我们要求总和时,有一个明确定义的算法来获得一个独特的解决方案 pi值的平方尽可能小。事实上,即使我们有任意数量的平均值,这种说法也是正确的。但是,由于一般问题的解决方案非常简单,因此无需调用矩阵库。为了完成,我将提出一般问题的解决方案,而不仅仅是3个值。

一般问题

给定实数N和m实数值ai,其中1 <= i <= m,找到一组m值pi,使得sum(pi)= 1并且sum(pi * ai)= N具有最小可能的sum(pi ^ 2)值。

解决方案如下:

pi = ( sum(aj^2) - (N + ai) * sum(aj) + m * N * ai ) / D

,其中

D = m * sum(aj^2) - ( sum(aj) )^2

sum(aj) = a1 + a2 + ... + am

sum(aj^2) = a1^2 + a2^2 + ... + am^2

证明(草拟,而非详细信息)

定义数量

S = sum(pi^2) - U * ( sum(pi) - 1 ) - V * ( sum(pi*ai) - N )

其中U和V(所谓的拉格朗日乘数)是要确定的常数。注意,如果/当pi值满足问题的条件时,S减少到sum(pi ^ 2),即,它们总和为1并且它们是导致N的ai值的平均中的权重。但是,在我们施加这些条件之前,S是pi值的一些复杂函数。

现在假设我们想要在所有可能的pi值选择中最小化S的值。 S达到极值(最小值或最大值)的必要条件是它相对于pi值的一阶偏导数都消失了:

dS/dpi = 2 * pi - U - V * ai = 0

这组m方程给出了使S成为极值的pi值:

2 * pi = U + V * ai

现在,为了找到U和V,在i上求和上述等式,并将相同的等式乘以ai乘以i。这给了我们2个方程式

2 * sum(pi)    = U * m       + V * sum(ai)
2 * sum(pi*ai) = U * sum(ai) + V * sum(ai^2)

但现在我们强加问题的条件并设置sum(pi)= 1和sum(pi * ai)= N并获得

    2 = U * m       + V * sum(ai)
2 * N = U * sum(ai) + V * sum(ai^2)

接下来我们求解U和V然后将它们插回pi值的等式​​中,结果就是我之前引用的。最后,通过查看二阶偏导数,我们可以看到,如果pi值为正,极值实际上是最小值:

d^2S/dpi^2 = pi

minimum  <=>  d^2S/dpi^2 > 0  <=>  p1 > 0

BOTTOM LINE

我说要忽略我最初提出的随机选择值的建议,而是选择我刚才描述的解决方案。它的独特性和计算非常简单。