标准差?

我需要计算一个通用列表的标准差。我将尝试包含我的代码。它是一个包含数据的通用列表。数据主要是 float 和 int。下面是我的相关代码,但没有涉及太多细节:

namespace ValveTesterInterface
{
public class ValveDataResults
{
private List<ValveData> m_ValveResults;


public ValveDataResults()
{
if (m_ValveResults == null)
{
m_ValveResults = new List<ValveData>();
}
}


public void AddValveData(ValveData valve)
{
m_ValveResults.Add(valve);
}

下面是需要计算标准差的函数:

        public float LatchStdev()
{


float sumOfSqrs = 0;
float meanValue = 0;
foreach (ValveData value in m_ValveResults)
{
meanValue += value.LatchTime;
}
meanValue = (meanValue / m_ValveResults.Count) * 0.02f;


for (int i = 0; i <= m_ValveResults.Count; i++)
{
sumOfSqrs += Math.Pow((m_ValveResults - meanValue), 2);
}
return Math.Sqrt(sumOfSqrs /(m_ValveResults.Count - 1));


}
}
}

忽略 LatchStdev ()函数中的内容,因为我确信它不正确。这只是我可怜的尝试,计算圣开发。我知道如何使用双精度列表,但不知道如何使用通用数据列表。如果有人有这方面的经验,请帮助。

95463 次浏览

上面的例子有点不正确,如果总体集为1,除数可能为零。下面的代码比较简单,给出了“填充标准差”的结果。(http://en.wikipedia.org/wiki/Standard_deviation)

using System;
using System.Linq;
using System.Collections.Generic;


public static class Extend
{
public static double StandardDeviation(this IEnumerable<double> values)
{
double avg = values.Average();
return Math.Sqrt(values.Average(v=>Math.Pow(v-avg,2)));
}
}

尽管公认的答案似乎在数学上是正确的,但从编程的角度来看却是错误的——它将同一个序列枚举了4次。如果底层对象是一个列表或数组,这可能没问题,但是如果输入是一个经过过滤的/聚合的/etc linq 表达式,或者如果数据直接来自数据库或网络流,这将导致更低的性能。

我强烈建议不要重新发明轮子,而是使用一个更好的开源数学库 Math.NET。我们公司一直在使用这种即兴演奏,对其性能感到非常满意。

PM > 安装-软件包数字网络

var populationStdDev = new List<double>(1d, 2d, 3d, 4d, 5d).PopulationStandardDeviation();


var sampleStdDev = new List<double>(2d, 3d, 4d).StandardDeviation();

有关更多信息,请参见 http://numerics.mathdotnet.com/docs/DescriptiveStatistics.html

最后,对于那些希望得到尽可能快的结果和牺牲一些精度的人,阅读“一次性”算法 https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods

我知道你在做什么,我也用了类似的东西。在我看来,你做得还不够。我倾向于将所有数据处理封装到一个单独的类中,这样我就可以缓存计算出来的值,直到列表发生变化。 例如:

public class StatProcessor{
private list<double> _data; //this holds the current data
private _avg; //we cache average here
private _avgValid; //a flag to say weather we need to calculate the average or not
private _calcAvg(); //calculate the average of the list and cache in _avg, and set _avgValid
public double average{
get{
if(!_avgValid) //if we dont HAVE to calculate the average, skip it
_calcAvg(); //if we do, go ahead, cache it, then set the flag.
return _avg; //now _avg is garunteed to be good, so return it.
}
}
...more stuff
Add(){
//add stuff to the list here, and reset the flag
}
}

您会注意到,使用这种方法,只有第一个平均值请求实际上计算了平均值。之后,只要我们不从列表中添加(或删除或修改任何内容,但显示的是 arnt)任何内容,我们就可以得到基本上没有内容的平均值。

此外,由于平均值用于标准差的算法,因此先计算标准差将免费提供平均值,而先计算平均值将在标准偏差计算中给我们带来一点性能提升,前提是我们记得检查标志。

而且!像 average 函数这样的地方,无论如何你已经在遍历每个值了,是缓存最小值和最大值的好时机。当然,对这些信息的请求首先需要检查它们是否已经被缓存,与仅仅使用列表查找最大值相比,这可能会导致相对的减速,因为它会做所有额外的工作来设置所有相关的缓存,而不仅仅是你访问的那个缓存。