提问人:Loc 提问时间:9/25/2023 最后编辑:Loc 更新时间:9/27/2023 访问量:144
如何计算累积几何平均值?
How to calculate cumulative geometric mean?
问:
我正在寻找使用 O(1) 空间计算累积几何平均值,其中输入是未知数字流。批次 = 1。我有这个例子,它与我试图解决的问题非常接近:
count = 1
geo_avg = 0
while True:
number = input("Enter number: ")
geo_avg = ((1 + float(number)) * (1 + geo_avg)) ** (1 / count) - 1
print("current geometric average", geo_avg, "\n")
count += 1
我知道这是错误的。我想我可能不得不删除以前的几何平均值,然后计算当前的几何平均值,但这听起来也不对。任何关于使用什么是正确方程式的评论/提示都将非常有用。
答:
扩展评论中提到的想法:
import math
def running_geo_mean(x):
sum_log = 0
count = 0
mean = []
for elem in x:
sum_log += math.log(elem)
count += 1
mean.append(math.exp(sum_log / count))
return mean
用法示例:
x = [i + 1 for i in range(10)]
print(running_geo_mean(x))
[1.0, 1.414213562373095, 1.8171205928321397, 2.213363839400643, 2.6051710846973517, 2.993795165523909, 3.3800151591412964, 3.764350599503129, 4.1471662743969135, 4.528728688116766]
评论
geometric_mean
如果 g_n 是 n 个数字的几何平均值,则要包含另一个数字 x_{n+1},则新的几何平均值为
g_{n+1} = (x_{n+1} * ((g_n) ^ n)) ^ (1/(n+1))
不过,这个公式在实践中可能会引入很多舍入错误。如果保留正在运行的产品
(g_n) ^ n = prod{i = 1 to n} x_i = P_n
它应该返回更好的准确性。如果要包含 m 个数字,则x_{n+1},...,x_{n+m},然后计算
p = prod_{i = n+1 to n+m} x_i
先,然后
P_{n+m} = (p * P_n)
g_{n+m} = P_{n+m} ^ (1/(n+m))
如果有P_n溢出的危险,那么你可以按照他的建议对日志进行求和。我预计这会更慢,并且通常具有更高的舍入误差,但溢出的可能性要小得多。
L_n = sum_{i = 1 to n} ln(x_i) = n * ln(g_n)
g_n = exp(L_n/n)
然后对于另一个 m 个数字,计算
l = sum_{i = n+1 to n+m} ln(x_i)
L_{n+m} = l + L_n
g_{n+m} = exp(L_{n+m}/(n+m))
要计算尺寸的运行几何平均值,您可以跟踪最后一个数字和当前乘积。当您有一个新号码时,您将要替换的数字除以要添加的数字,然后乘以要添加的数字。n
n
这是在 Python 中执行此操作的一种方法。
import functools
import math
def produce_geometric_average(n: int):
lst = []
log_prod = 0
idx = 0
def geometric_average(x: float):
nonlocal lst
nonlocal log_prod
nonlocal idx
log_x = math.log(x)
if len(lst) < n:
lst.append(log_x)
log_prod = functools.reduce(lambda x, y: x + y, lst)
else:
idx_to_replace = idx % n
old_log_x = lst[idx_to_replace]
log_prod = log_prod - old_log_x + log_x
lst[idx_to_replace] = log_x
idx += 1
return math.exp(log_prod / len(lst))
# c.f., return math.exp(functools.reduce(lambda x, y: x + y, lst) / len(lst))
return geometric_average
geometric_average = produce_geometric_average(3)
for x in [1.0, 1.0, 8.0, 27.0, 64.0, 125.0, 216.0]:
print(geometric_average(x))
输出
1.0
1.0
2.0
6.000000000000001
23.999999999999993
59.999999999999986
119.99999999999997
评论
long
2
64
long
**
prod
float
prod
RunningStatistics
您可以跟踪对数总和数字计数,以便将几何平均值计算为对数刻度中的算术平均值,如维基百科上所述。
下面是使用闭包的 Python 实现。
from math import log, exp
def make_geometric_averager():
log_sum = 0
number_count = 0
def geometric_mean(x: float):
nonlocal log_sum, number_count
log_sum += log(x)
number_count += 1
return exp(log_sum / number_count)
return geometric_mean
# Example
geometric_averager = make_geometric_averager()
print(geometric_averager(10)) # 10.0
print(geometric_averager(100)) # 31.62
print(geometric_averager(1000)) # 99.99, numerical imprecision
这通常是单行的,给定前一个元组 (gmn, n) 和新值 x,返回 (gm n+1,n+1) 的新元组
def update_geo_mean(gm_n, x):
gm, n = gm_n
return ((gm**n * x)**(1.0/(n+1)), n+1)
可以使用 exp/log 来避免溢出/下溢。
以 (1,0) 元组开头
带 log/exp 的版本
import numpy as np
def update_geo_mean(gm_n, x):
gm, n = gm_n
return (np.exp((n * np.log(gm) + np.log(x))/(n+1)), n+1)
更新
可以将元组 (gmn, n) 和 update_geo_mean() 视为 Monoid 的例子,其中恒等元素是 (1,0) 元组。单元二进制操作将是
def geo_mean_binary(gm_n, gm_m):
g_n, n = gm_n
g_m, m = gm_m
return (np.exp((n * np.log(g_n) + m*np.log(g_m))/(n+m)), n+m)
和
def update_geo_mean(gm_n, x):
return geo_mean_binary(gm_n, (x,1))
上一个:为什么答案不同?
下一个:我不明白为什么它会这样工作
评论
ln_sum += ln(1 + number); geo_avg = e^((1/count) * ln_sum) - 1
cumprod(x)**(1/range(1,len(x) + 1)
prod =* float(number); geo_avg = prod**(1/count); count +=1
geometric_averager(x)
x < 0