从 C# 数组计算最小值、最大值、平均值、中值和标准差的最快方法是什么?

分享于2022年07月17日 c# max mean min standard-deviation 问答
【问题标题】:从 C# 数组计算最小值、最大值、平均值、中值和标准差的最快方法是什么?(What is the fastest way to calculate min, max, mean, median and standard deviation from C# array?)
【发布时间】:2022-01-27 19:14:45
【问题描述】:

我有一个更大的数组或未排序的双精度列表,我想以最有效的方式计算最小值、最大值、平均值、中值和标准差。当然,我可以简单地使用 Linq 来逐个计算,但我认为可以更快。示例代码:

var list = new List(){1.0, 2.5, 0.11, 0.7, 8.2, 3.4, 1.0};
var (min, max, mean, median, std) = CalculateMetrics(list);

private (double, double, double, double, double) CalculateMetrics(List list) {
    // TODO
}

那么最有效的方法是什么?使用库对我来说也很好。

  • 当你说“更大”时,比如多大? 500? 5k? 5M? 5B?如果您估计了潜在的数组大小,则可以选择更好的算法。考虑到所有相关的开销,可能不需要对大小约为 1k 的原始数组进行大量优化。

【解决方案1】:

您想要的所有描述性统计 除了中位数 都可以通过您的 list 一次性计算出来。获得标准差的诀窍是累积样本的总和和平方和。这是一个例子。

int count = 0;
double sum = 0.0;
double sumsq = 0.0;
double max = double.MinValue;
double min = double.MaxValue;

foreach (double sample in list)
{
    count++;
    sum += sample;
    sumsq += sample * sample;
    if (sample > max) max = sample;
    if (sample < min) min = sample;
}

double mean = sum / count;
double stdev = Math.Sqrt((sumsq / count) - (mean * mean));

因为这只会通过列表一次,所以它适用于任何 IEnumerable 样本集合,并且与 LINQ 兼容。

显然,这是快速不脏的示例代码。我把它留给你把它构建成一个有用的功能。

它将对空的 list 进行除法检查。而且,如果您有非常大的数字或非常长的列表,那么计算 stdev 时的减法可能会丢失精度并返回一个无用的数字。

但它适用于大多数应用程序。

  • OP 也需要中位数,为此需要对列表进行排序以在 O(n)
  • 哦,你说得对,我错过了中位数要求。正如您所提到的,除非列表 先验 已知要排序,否则单程 O(n) 就这么多。你也可以使用 list.Median() 来获取中位数;它进行了适当的优化。