如何迭代计算运行加权平均值,使最后的值最重?

Suz*_*ioc 13 iteration algorithm weighted-average

我想实现一个迭代算法,计算加权平均值.具体权重法无关紧要,但最新值应接近1,最接近0.

算法应该是迭代的.即它不应该记住以前的所有值.它应该只知道一个最新的值和任何关于过去的汇总信息,比如以前的平均值,总和,计数等.

可能吗?

例如,以下算法可以是:

void iterate(double value) {
   sum *= 0.99;
   sum += value;
   count++;
   avg = sum / count;
}
Run Code Online (Sandbox Code Playgroud)

它会给指数减少的重量,这可能不好.是否有可能逐步减轻体重?

编辑1

称重法的要求如下:

1)重量减少到过去2)我有一些平均或特征持续时间,以便这个持续时间较旧的值比新的更小的值3)我应该能够设置这个持续时间

编辑2

我需要以下内容.假设v_i是值,其中v_1第一个是.还假设w_i是权重.但是w_0最后一次.

所以,在第一个价值来之后,我有第一个平均值

 a_1 = v_1 * w_0
Run Code Online (Sandbox Code Playgroud)

在第二个值v_2来之后,我应该有平均值

 a_2 = v_1 * w_1 + v_2 * w_0
Run Code Online (Sandbox Code Playgroud)

我应该有下一个值

 a_3 = v_1 * w_2 + v_2 * w_1 + v_3 * w_0
Run Code Online (Sandbox Code Playgroud)

请注意,当我按照值序列移动时,重量轮廓随着我移动.

即每个值都没有自己的重量.我的目标是在过去的同时降低体重.

nin*_*cko 24

先来一点背景.如果我们保持正常平均值,它会像这样:

average(a) = 11
average(a,b) = (average(a)+b)/2
average(a,b,c) = (average(a,b)*2 + c)/3
average(a,b,c,d) = (average(a,b,c)*3 + d)/4
Run Code Online (Sandbox Code Playgroud)

正如你在这里看到的,这是一个"在线"算法,我们只需要跟踪数据:1)平均值中的总数,2)平均值本身.然后我们可以将总数除以总数,加上新数字,然后除以新总数.

加权平均值略有不同.这取决于什么样的加权平均值.例如,如果您定义:

weightedAverage(a,wa, b,wb, c,wc, ..., z,wz) = a*wa + b*wb + c*wc + ... + w*wz
 or
weightedAverage(elements, weights) = elements·weights
Run Code Online (Sandbox Code Playgroud)

...那么除了添加新元素*重量之外你不需要做任何事情!但是,如果您将加权平均值定义为类似于概率的预期值:

weightedAverage(elements,weights) = elements·weights / sum(weights)
Run Code Online (Sandbox Code Playgroud)

...然后你需要跟踪总重量.而不是不计算元素的总数,而不是重量,添加新元素*权重,然后除以新的总重量.

或者你不需要分开,如下所示:你只能跟踪一个闭包或一个物体中的临时点积和重量总和,并在你屈服时将它除去(这可以帮助避免数值不准确)复合舍入错误).

在python中,这将是:

def makeAverager():
    dotProduct = 0
    totalWeight = 0

    def averager(newValue, weight):
        nonlocal dotProduct,totalWeight

        dotProduct += newValue*weight
        totalWeight += weight
        return dotProduct/totalWeight

    return averager
Run Code Online (Sandbox Code Playgroud)

演示:

>>> averager = makeAverager()
>>> [averager(value,w) for value,w in [(100,0.2), (50,0.5), (100,0.1)]]
[100.0, 64.28571428571429, 68.75]
>>> averager(10,1.1)
34.73684210526316
>>> averager(10,1.1)
25.666666666666668
>>> averager(30,2.0)
27.4
Run Code Online (Sandbox Code Playgroud)


nin*_*cko 5

>但我的任务是在每次新值到达时重新计算平均值,并对旧值进行重新加权。–OP

您的任务几乎总是不可能完成的,即使采用非常简单的加权方案。

您要求使用 O(1) 内存,使用不断变化的加权方案产生平均值。例如, { values·weights1, (values+[newValue2])·weights2, (values+[newValue2,newValue3])·weights3, ...} 作为新值被传入,对于一些几乎任意改变的权重序列。由于注入性,这是不可能的。一旦将这些数字合并在一起,就会丢失大量信息。例如,即使您有权重向量,也无法恢复原始值向量,反之亦然。我能想到的只有两种情况你可以摆脱这个:

  • 恒定权重,例如 [2,2,2,...2]:这相当于在线平均算法,您不想要它,因为旧值没有被“重新加权”。
  • 先前答案的相对权重不会改变。例如,您可以对 进行权重[8,4,2,1],并添加一个具有任意权重的新元素,例如...+[1],但您必须将之前的所有元素增加相同的乘法因子,例如[16,8,4,2]+[1]。因此,在每一步,您都会添加一个新的任意权重,以及对过去的新任意重新缩放,因此您有 2 个自由度(如果您需要保持点积归一化,则只有 1 个)。你得到的权重向量看起来像:

 

[w0]
[w0*(s1), w1]
[w0*(s1*s2), w1*(s2), w2]
[w0*(s1*s2*s3), w1*(s2*s3), w2*(s3), w3]
...
Run Code Online (Sandbox Code Playgroud)

因此,您可以使任何加权方案看起来都可行(除非您需要通过权重总和使事物标准化,在这种情况下,您必须将新平均值除以新总和,您可以通过仅保留 O (1) 记忆)。只需将先前的平均值乘以新的s(这将隐式地将点积分布到权重中),然后添加新的+w*newValue.


Jar*_*łka 2

我想你正在寻找这样的东西:

void iterate(double value) {
    count++;

    weight = max(0, 1 - (count / 1000));

    avg = ( avg * total_weight * (count - 1)  + weight * value) / (total_weight * (count - 1) + weight)
    total_weight += weight;
}
Run Code Online (Sandbox Code Playgroud)