如何确定一组值的标准偏差(stddev)?

dea*_*ted 45 c# math statistics numerical

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

Jai*_*ime 100

虽然平方和算法在大多数情况下都可以正常工作,但如果处理非常大的数字,它可能会造成很大的麻烦.你基本上可能会出现负差异......

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

到目前为止,计算标准偏差的最佳方法是Welford的方法.我的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));
}
Run Code Online (Sandbox Code Playgroud)

如果您拥有整个人口(而不是样本人口),那么请使用return Math.Sqrt(S / (k-1));.

编辑:我根据杰森的评论更新了代码......

编辑:我也根据Alex的评论更新了代码......

  • 现在看看你做了什么.你给了我一些新的东西要学习.你是野兽. (7认同)
  • John Cook在http://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/上有一篇关于大值标准偏差的文章很好,后续描述算法背后的原因http://www.johndcook.com/blog/2008/09/28/theoretical-explanation-for-numerical-results/. (6认同)
  • 实际上,如果事先有整个列表,校正的2遍算法就可以了(参见例如Numerical Recipes).此方法是您有一个不想存储的*stream*值. (3认同)
  • +1:我读过Knuth对此的评论,但从未知道它被称为Welford的方法.仅供参考,你可以消除k == 1的情况,它只是有效. (2认同)
  • OH:你忘记了N分频或N-1分频. (2认同)
  • 实际上,你的变量k最终比实际的点数大1,因为它从1开始(例如,有2个点,k = 3).这意味着您需要在最后一步中减去额外的1,因此整个群体的k-1和样本总数的k-2. (2认同)
  • 或者,您可以在零处开始k,但先将其递增而不是最后一次.然后在结尾处将其设置回k-1. (2认同)

Ped*_*o77 7

Jaime的解决方案比Jaime 快10倍,但请注意,Jaime指出:

"虽然平方和算法在大多数情况下都可以正常工作,但是如果处理非常大的数字会导致大麻烦.你基本上可能会出现负差异"

如果你认为你正在处理非常大的数字或非常大量的数字,你应该使用两种方法计算,如果结果相同,你肯定知道你可以使用"我的"方法.

    public static double StandardDeviation(double[] data)
    {
        double stdDev = 0;
        double sumAll = 0;
        double sumAllQ = 0;

        //Sum of x and sum of x²
        for (int i = 0; i < data.Length; i++)
        {
            double x = data[i];
            sumAll += x;
            sumAllQ += x * x;
        }

        //Mean (not used here)
        //double mean = 0;
        //mean = sumAll / (double)data.Length;

        //Standard deviation
        stdDev = System.Math.Sqrt(
            (sumAllQ -
            (sumAll * sumAll) / data.Length) *
            (1.0d / (data.Length - 1))
            );

        return stdDev;
    }
Run Code Online (Sandbox Code Playgroud)


Ale*_*exB 5

Jaime 接受的答案很好,除了你需要在最后一行除以 k-2(你需要除以“number_of_elements-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));
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*sic 5

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();
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅人口标准偏差。