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)
>但我的任务是在每次新值到达时重新计算平均值,并对旧值进行重新加权。–OP
您的任务几乎总是不可能完成的,即使采用非常简单的加权方案。
您要求使用 O(1) 内存,使用不断变化的加权方案产生平均值。例如, { values·weights1, (values+[newValue2])·weights2, (values+[newValue2,newValue3])·weights3, ...} 作为新值被传入,对于一些几乎任意改变的权重序列。由于注入性,这是不可能的。一旦将这些数字合并在一起,就会丢失大量信息。例如,即使您有权重向量,也无法恢复原始值向量,反之亦然。我能想到的只有两种情况你可以摆脱这个:
[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.
我想你正在寻找这样的东西:
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)
| 归档时间: |
|
| 查看次数: |
18795 次 |
| 最近记录: |