通用列表的标准差? [复制]
Posted
技术标签:
【中文标题】通用列表的标准差? [复制]【英文标题】:Standard deviation of generic list? [duplicate] 【发布时间】:2011-03-09 16:10:37 【问题描述】:我需要计算一个通用列表的标准差。我将尝试包含我的代码。它是一个包含数据的通用列表。数据主要是浮点数和整数。这是我的代码,与它相关,但没有详细说明:
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的糟糕尝试。我知道如何处理双打列表,但不知道通用数据列表。如果有人有这方面的经验,请帮助。
【问题讨论】:
【参考方案1】:This article 应该可以帮助您。它创建了一个函数来计算double
值序列的偏差。您所要做的就是提供一系列适当的数据元素。
得到的函数是:
private double CalculateStandardDeviation(IEnumerable<double> values)
double standardDeviation = 0;
if (values.Any())
// 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.
standardDeviation = Math.Sqrt((sum) / (values.Count()-1));
return standardDeviation;
这很容易适应任何泛型类型,只要我们为正在计算的值提供选择器。 LINQ 非常适合这一点,Select
函数允许您从自定义类型的通用列表中投影一系列数值,以计算其标准偏差:
List<ValveData> list = ...
var result = list.Select( v => (double)v.SomeField )
.CalculateStdDev();
【讨论】:
@Tom Hangler,确保在文件顶部添加using System.Linq;
以包含 LINQ 函数库。这些包括Average()
和Select()
请注意,该算法实现了样本标准偏差,而不是“普通”标准偏差。
if(values.Count()>0)
行应该检查 > 1,因为你除以 values.Count() - 1
。
为了获得更快的性能(在我的机器上为 3.37 倍),请将这些项相乘而不是使用 Math.Pow:(d - avg) * (d - avg) 而不是:Math.Pow(d -平均,2)
double sum = values.Sum(d => (d - avg) * (d - avg));【参考方案2】:
即使接受的答案在数学上看起来是正确的,但从编程的角度来看它是错误的 - 它枚举了相同的序列 4 次。如果底层对象是列表或数组,这可能没问题,但如果输入是过滤/聚合/等 linq 表达式,或者数据直接来自数据库或网络流,这将导致性能低得多。
我强烈建议不要重新发明***,而是使用更好的开源数学库之一 Math.NET。我们公司一直在使用该库,并且对性能非常满意。
PM> 安装包 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】:我明白你在做什么,我使用类似的东西。在我看来,你走得还不够远。我倾向于将所有数据处理封装到一个类中,这样我就可以缓存计算的值,直到列表发生变化。 例如:
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
您会注意到,使用此方法时,只有第一个求平均值请求才会实际计算平均值。在那之后,只要我们不从列表中添加(或删除或修改,但那些未显示的)任何内容,我们基本上可以得到平均值。
另外,由于算法中使用了平均值来计算标准差,所以先计算标准差可以免费得到平均值,而先计算平均值会给我们在标准差计算中带来一点性能提升,假设我们记得检查标志。
此外!像平均函数这样的地方,无论如何你已经遍历了每个值,是缓存最小值和最大值之类的东西的好时机。当然,对这些信息的请求需要首先检查它们是否已被缓存,与仅使用列表查找最大值相比,这可能会导致相对减速,因为它会完成所有额外的工作来设置所有相关的缓存,而不仅仅是一个你的访问。
【讨论】:
【参考方案4】:上面的例子有点不正确,如果您的总体集为 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)));
【讨论】:
这应该是答案,它计算标准偏差,而不是真正计算样本标准偏差的 LBushkin 的答案 +1 这是实际的标准偏差(又称总体标准偏差),而不是 LBushkin 回答中的样本标准偏差。 return Math.Sqrt(values.Average(v=> (v-avg) * (v-avg)));在我的机器上快 3.37 倍。 Math.Pow() 比普通乘法慢得多。 @BlueSky 感谢您进行基准测试!我喜欢有两种选择都可以清楚地看到。 Math.Pow() 可能更具可读性,但您的代码性能更高,因此人们可以选择适合他们场景的内容。 从数学上看,这是正确的答案。但是,您应该绝对避免在生产中使用此代码:参数是 IEnumerable以上是关于通用列表的标准差? [复制]的主要内容,如果未能解决你的问题,请参考以下文章