C# 如何确定一组值的标准偏差(STDEV)?

C# 如何确定一组值的标准偏差(STDEV)?,c#,math,statistics,numerical,C#,Math,Statistics,Numerical,我需要知道与一组数字相比,一个数字是否超出平均值的1 stddev,等等。通过累积平均值和均方值,可以避免对数据进行两次传递 cnt = 0 mean = 0 meansqr = 0 loop over array cnt++ mean += value meansqr += value*value mean /= cnt meansqr /= cnt 形成 sigma = sqrt(meansqr - mean^2) cnt/(cnt-1)的系数通常也是合适的 顺便

我需要知道与一组数字相比,一个数字是否超出平均值的1 stddev,等等。

通过累积平均值和均方值,可以避免对数据进行两次传递

cnt = 0
mean = 0
meansqr = 0
loop over array
    cnt++
    mean += value
    meansqr += value*value
mean /= cnt
meansqr /= cnt
形成

sigma = sqrt(meansqr - mean^2)
cnt/(cnt-1)
的系数通常也是合适的

顺便说一句——在调用
Average
时,第一次传递中的数据和答案是隐藏的。在一个小的列表中,这种事情当然是微不足道的,但是如果列表超过了缓存的大小,甚至超过了工作集的大小,这就变成了一个出价交易。

代码片段:

public static double StandardDeviation(List<double> valueList)
{
    if (valueList.Count < 2) return 0.0;
    double sumOfSquares = 0.0;
    double average = valueList.Average(); //.NET 3.0
    foreach (double value in valueList) 
    {
        sumOfSquares += Math.Pow((value - average), 2);
    }
    return Math.Sqrt(sumOfSquares / (valueList.Count - 1));
}
公共静态双标准偏差(列表值列表)
{
如果(valueList.Count<2)返回0.0;
双平方和=0.0;
双平均值=valueList.average();/.NET 3.0
foreach(值列表中的双值)
{
sumOfSquares+=数学功率((值-平均值),2);
}
返回Math.Sqrt(sumOfSquares/(valueList.Count-1));
}

虽然平方和算法在大多数情况下运行良好,但如果处理的是非常大的数字,它可能会带来很大的麻烦。基本上你可能会得到一个负的方差

另外,不要,永远,永远,永远,计算a^2为pow(a,2),a*a几乎肯定更快

到目前为止,计算标准偏差的最佳方法是。我的C非常生锈,但它可能看起来像:

public static double StandardDeviation(List<double> valueList)
{
    double M = 0.0;
    double S = 0.0;
    int k = 1;
    foreach (double value in valueList) 
    {
        double tmpM = M;
        M += (value - tmpM) / k;
        S += (value - tmpM) * (value - M);
        k++;
    }
    return Math.Sqrt(S / (k-2));
}
公共静态双标准偏差(列表值列表)
{
双M=0.0;
双S=0.0;
int k=1;
foreach(值列表中的双值)
{
双tmpM=M;
M+=(值-tmpM)/k;
S+=(值-tmpM)*(值-M);
k++;
}
返回数学Sqrt(S/(k-2));
}
如果您拥有整个总体(与样本总体相反),那么使用
return Math.Sqrt(S/(k-1))

编辑:我已经根据Jason的评论更新了代码

/// <summary>
/// Calculates standard deviation, same as MATLAB std(X,0) function
/// <seealso cref="http://www.mathworks.co.uk/help/techdoc/ref/std.html"/>
/// </summary>
/// <param name="values">enumumerable data</param>
/// <returns>Standard deviation</returns>
public static double GetStandardDeviation(this IEnumerable<double> values)
{
    //validation
    if (values == null)
        throw new ArgumentNullException();

    int lenght = values.Count();

    //saves from devision by 0
    if (lenght == 0 || lenght == 1)
        return 0;

    double sum = 0.0, sum2 = 0.0;

    for (int i = 0; i < lenght; i++)
    {
        double item = values.ElementAt(i);
        sum += item;
        sum2 += item * item;
    }

    return Math.Sqrt((sum2 - sum * sum / lenght) / (lenght - 1));
}
编辑:我还根据Alex的评论更新了代码…

//
/// <summary>
/// Calculates standard deviation, same as MATLAB std(X,0) function
/// <seealso cref="http://www.mathworks.co.uk/help/techdoc/ref/std.html"/>
/// </summary>
/// <param name="values">enumumerable data</param>
/// <returns>Standard deviation</returns>
public static double GetStandardDeviation(this IEnumerable<double> values)
{
    //validation
    if (values == null)
        throw new ArgumentNullException();

    int lenght = values.Count();

    //saves from devision by 0
    if (lenght == 0 || lenght == 1)
        return 0;

    double sum = 0.0, sum2 = 0.0;

    for (int i = 0; i < lenght; i++)
    {
        double item = values.ElementAt(i);
        sum += item;
        sum2 += item * item;
    }

    return Math.Sqrt((sum2 - sum * sum / lenght) / (lenght - 1));
}
///计算标准偏差,与MATLAB std(X,0)函数相同 /// /// ///可枚举数据 ///标准差 公共静态双GetStandardDeviation(此IEnumerable值) { //验证 如果(值==null) 抛出新ArgumentNullException(); int lenght=values.Count(); //从除法中节省0 如果(长度==0 | |长度==1) 返回0; 双和=0.0,sum2=0.0; 对于(int i=0;i
我发现Rob有用的答案与我在excel中看到的不太相符。为了匹配excel,我将valueList的平均值传递到标准偏差计算中

这是我的两分钱。。。很明显,你可以从函数中的valueList中计算移动平均值(ma)——但在需要标准偏差之前,我碰巧已经计算过了

public double StandardDeviation(List<double> valueList, double ma)
{
   double xMinusMovAvg = 0.0;
   double Sigma = 0.0;
   int k = valueList.Count;


  foreach (double value in valueList){
     xMinusMovAvg = value - ma;
     Sigma = Sigma + (xMinusMovAvg * xMinusMovAvg);
  }
  return Math.Sqrt(Sigma / (k - 1));
}       
公共双标准偏差(列表值列表,双ma)
{
双xMinusMovAvg=0.0;
双西格玛=0.0;
int k=valueList.Count;
foreach(值列表中的双值){
xMinusMovAvg=值-ma;
西格玛=西格玛+(xMinusMovAvg*xMinusMovAvg);
}
返回数学Sqrt(Sigma/(k-1));
}       

Jaime接受的答案很好,除了最后一行需要除以k-2(需要除以“元素的数量-1”)。 更好的是,从0开始计算k:

public static double StandardDeviation(List<double> valueList)
{
    double M = 0.0;
    double S = 0.0;
    int k = 0;
    foreach (double value in valueList) 
    {
        k++;
        double tmpM = M;
        M += (value - tmpM) / k;
        S += (value - tmpM) * (value - M);
    }
    return Math.Sqrt(S / (k-1));
}
公共静态双标准偏差(列表值列表)
{
双M=0.0;
双S=0.0;
int k=0;
foreach(值列表中的双值)
{
k++;
双tmpM=M;
M+=(值-tmpM)/k;
S+=(值-tmpM)*(值-M);
}
返回数学Sqrt(S/(k-1));
}

带有扩展方法的

使用系统;
使用System.Collections.Generic;
名称空间SampleApp
{
内部课程计划
{
私有静态void Main()
{
列表数据=新列表{1,2,3,4,5,6};
双平均值=数据。平均值();
双方差=data.variance();
双sd=数据。标准偏差();
WriteLine(“均值:{0},方差:{1},标准差:{2}”,均值,方差,标准差);
Console.WriteLine(“按任意键继续…”);
Console.ReadKey();
}
}
公共静态类MyListExtensions
{
公共静态双平均值(此列表值)
{
返回值.Count==0?0:values.Mean(0,values.Count);
}
公共静态双平均值(此列表值,int开始,int结束)
{
双s=0;
for(int i=start;i0)n-=1;
收益方差/(n);
}
公共静态双标准偏差(此列表值)
{
返回值.Count==0?0:values.StandardDeviation(0,values.Count);
}
公共静态双标准偏差(此列表值,int开始,int结束)
{
双平均值=值。平均值(开始、结束);
双方差=值。方差(平均值、开始值、结束值);
var populationStdDev = new List<double>(1d, 2d, 3d, 4d, 5d).PopulationStandardDeviation();

var sampleStdDev = new List<double>(2d, 3d, 4d).StandardDeviation();
public final class StatMeasure {
  private StatMeasure() {}

  public interface Stats1D {

    /** Add a value to the population */
    void addValue(double value);

    /** Get the mean of all the added values */
    double getMean();

    /** Get the standard deviation from a sample of the population. */
    double getStDevSample();

    /** Gets the standard deviation for the entire population. */
    double getStDevPopulation();
  }

  private static class WaldorfPopulation implements Stats1D {
    private double mean = 0.0;
    private double sSum = 0.0;
    private int count = 0;

    @Override
    public void addValue(double value) {
      double tmpMean = mean;
      double delta = value - tmpMean;
      mean += delta / ++count;
      sSum += delta * (value - mean);
    }

    @Override
    public double getMean() { return mean; }

    @Override
    public double getStDevSample() { return Math.sqrt(sSum / (count - 1)); }

    @Override
    public double getStDevPopulation() { return Math.sqrt(sSum / (count)); }
  }

  private static class StandardPopulation implements Stats1D {
    private double sum = 0.0;
    private double sumOfSquares = 0.0;
    private int count = 0;

    @Override
    public void addValue(double value) {
      sum += value;
      sumOfSquares += value * value;
      count++;
    }

    @Override
    public double getMean() { return sum / count; }

    @Override
    public double getStDevSample() {
      return (float) Math.sqrt((sumOfSquares - ((sum * sum) / count)) / (count - 1));
    }

    @Override
    public double getStDevPopulation() {
      return (float) Math.sqrt((sumOfSquares - ((sum * sum) / count)) / count);
    }
  }

  /**
   * Returns a way to measure a population of data using Waldorf's method.
   * This method is better if your population or values are so large that
   * the sum of x-squared may overflow. It's also probably faster if you
   * need to recalculate the mean and standard deviation continuously,
   * for example, if you are continually updating a graphic of the data as
   * it flows in.
   *
   * @return A Stats1D object that uses Waldorf's method.
   */
  public static Stats1D getWaldorfStats() { return new WaldorfPopulation(); }

  /**
   * Return a way to measure the population of data using the sum-of-squares
   * method. This is probably faster than Waldorf's method, but runs the
   * risk of data overflow.
   *
   * @return A Stats1D object that uses the sum-of-squares method
   */
  public static Stats1D getSumOfSquaresStats() { return new StandardPopulation(); }
}
private double calculateStdDev(List<double> values)
{
    double average = values.Average();
    return Math.Sqrt((values.Select(val => (val - average) * (val - average)).Sum()) / values.Count);
}