首先简单介绍一下背景。如果我们使用普通平均数,它会是这样的:
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
正如您在这里看到的,这是一种“在线”算法,我们只需要跟踪两个数据片段: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
如果你定义的加权平均值类似于概率中的期望值,那么除了添加新元素和权重之外,你不需要做任何事情!
但是如果不是这样,你需要做一些修改。
weightedAverage(elements,weights) = elements·weights / sum(weights)
如果你需要跟踪总权重,那么你需要保持追踪。 不是通过元素总数来除以它,而是通过总权重来进行未除运算,加上新元素*权重,然后除以新的总权重。
或者你可以不用进行未除运算,如下所示:你可以在闭包或对象中跟踪临时点积和权重总和,并在生成时进行除法(这可以帮助避免由于复利舍入误差导致的数字不准确问题)。
在Python中,代码如下:
def makeAverager():
dotProduct = 0
totalWeight = 0
def averager(newValue, weight):
nonlocal dotProduct,totalWeight
dotProduct += newValue*weight
totalWeight += weight
return dotProduct/totalWeight
return averager
演示:
>>> 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