计算平均值的最佳方法是什么?有了这个问题,我想知道在数值意义上用于计算平均值的算法是最好的。它应该具有最小的舍入误差,不应对上溢或下溢等敏感。
谢谢。
附加信息:首选增量方法,因为值的数量可能不适合RAM(对大于4 GB的文件进行多次并行计算)。
答案 0 :(得分:8)
如果您想要O(N)算法,请查看Kahan summation。
答案 1 :(得分:6)
您可以查看http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.43.3535(Nick Higham,“浮点求和的准确性”,SIAM Journal of Scientific Computation,1993)。
如果我没记错的话,如果所有数字都是正数,则补偿求和(Kahan求和)是好的,至少与排序它们并按升序添加它们一样好(除非有非常多的数字)。如果有些数字为正数且有些数字为负数,则故事要复杂得多,以便取消。在这种情况下,有一个参数可以按降序添加它们。
答案 2 :(得分:4)
只是为了进一步讨论添加一个可能的答案:
逐步计算每一步的平均值:
AVG_n = AVG_(n-1)*(n-1)/ n + VALUE_n / n
或成对组合
AVG_(n_a + n_b)=(n_a * AVG_a + n_b * AVG_b)/(n_a + n_b)
(我希望公式足够清晰)
答案 3 :(得分:3)
按数量级的升序排序数字。总结它们,首先是低幅度。除以计数。
答案 4 :(得分:2)
一篇很晚的帖子,但由于我没有足够的声誉来发表评论,@Dave 的方法是 Gnu Scientific Library 使用的方法(截至 2020 年 12 月)。
这是从mean_source.c中提取的代码:
double FUNCTION (gsl_stats, mean) (const BASE data[], const size_t stride, const size_t size)
{
/* Compute the arithmetic mean of a dataset using the recurrence relation mean_(n) = mean(n-1) + (data[n] - mean(n-1))/(n+1) */
long double mean = 0;
size_t i;
for (i = 0; i < size; i++)
{
mean += (data[i * stride] - mean) / (i + 1);
}
return mean;
}
GSL 使用相同的算法来计算方差,毕竟它只是给定数字的平方差的平均值。
答案 5 :(得分:0)
我总是使用以下伪代码:
float mean=0.0; // could use doulbe
int n=0; // could use long
for each x in data:
++n;
mean+=(x-mean)/n;
我没有关于其稳定性的正式证据,但你可以看到我们不会遇到数值溢出问题,假设数据值表现良好。它在Knuth的计算机编程艺术
中被提及