我需要计算通用列表的标准偏差。我会尝试包含我的代码。它是一个包含数据的通用列表。数据主要是浮点数和整数。这是我的代码,它与之相关,但没有详细介绍:
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()函数中的内容,因为我确定它不对。这只是我对计算st dev的不良尝试。我知道如何处理双打列表,但不是通用数据列表列表。如果有人有这方面的经验,请帮助。
答案 0 :(得分:144)
上面的示例略有不正确,如果您的总体设置为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)));
}
}
答案 1 :(得分:61)
This article应该可以帮到你。它创建了一个计算double
值序列偏差的函数。您所要做的就是提供一系列适当的数据元素。
结果函数是:
private double CalculateStdDev(IEnumerable<double> values)
{
double ret = 0;
if (values.Count() > 0)
{
//Compute the Average
double avg = values.Average();
//Perform the Sum of (value-avg)_2_2
double sum = values.Sum(d => Math.Pow(d - avg, 2));
//Put it all together
ret = Math.Sqrt((sum) / (values.Count()-1));
}
return ret;
}
这很容易适应任何泛型类型,只要我们为计算的值提供选择器。 LINQ非常适用于此,Select
函数允许您从自定义类型的通用列表中投影一系列数值,以计算标准差:
List<ValveData> list = ...
var result = list.Select( v => (double)v.SomeField )
.CalculateStdDev();
答案 2 :(得分:18)
尽管接受的答案似乎在数学上是正确的,但从编程的角度来看它是错误的 - 它列举了相同的序列4次。如果底层对象是列表或数组,但如果输入是过滤/聚合/ etc linq表达式,或者如果数据直接来自数据库或网络流,这可能会导致性能低得多。
我强烈建议不要重新发明轮子并使用一个更好的开源数学库Math.NET。我们一直在公司使用lib,对性能非常满意。
PM&GT;安装包MathNet.Numerics
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
答案 3 :(得分:0)
我看到你在做什么,我使用类似的东西。在我看来,你还远远不够。我倾向于将所有数据处理封装到单个类中,这样我可以缓存计算的值,直到列表更改为止。 例如:
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)列表中的任何内容,我们就可以获得基本没有的平均值。
此外,由于平均值在算法中用于标准偏差,首先计算标准偏差将给我们免费的平均值,并且计算平均值首先会给我们在标准偏差计算中的一点性能提升,假设我们记得检查旗帜。
此外!像平均函数这样的地方,无论如何你已经遍历每个值,是一个很好的时间来缓存诸如最小值和最大值之类的东西。当然,对此信息的请求需要首先检查它们是否已被缓存,并且与仅使用列表查找最大值相比可能导致相对减速,因为它完成了设置所有相关缓存的所有额外工作,而不仅仅是一个你的访问。