web-dev-qa-db-ja.com

値のセットの標準偏差(stddev)を決定するにはどうすればよいですか?

数値のセットと比較した数値が、平均から1 stddevの外にあるかどうかなどを知る必要があります。

45

平方和アルゴリズムはほとんどの場合正常に機能しますが、非常に大きな数を扱う場合は大きな問題を引き起こす可能性があります。基本的に負の分散になる場合があります...

さらに、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));
}
_

whole母集団(sample母集団ではなく)がある場合は、return Math.Sqrt(S / (k-1));を使用します。

EDIT:Jasonの発言に従ってコードを更新しました...

EDIT:Alexの発言に従ってコードも更新しました...

100
Jaime

10倍高速 Jaimeよりも解決策ですが、注意それは、Jaimeが指摘したように:

「平方和アルゴリズムはほとんどの場合うまく機能しますが、非常に大きい数を扱う場合、大きなトラブルを引き起こす可能性があります。基本的に負の分散になる可能性があります。」

非常に大きな数または非常に多くの数を処理していると思われる場合は、両方の方法を使用して計算する必要があります。結果が等しい場合、「my」方法を使用できることは確かです。

    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;
    }
7
Pedro77

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));
}
5
AlexB

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();

詳細については、 PopulationStandardDeviation を参照してください。

4
Chris Marisic

コードスニペット:

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));
}
2
Demi

平均と平均二乗を累積することにより、データを2回通過することを回避できます。

_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)の係数も適切です。

BTW-- Demi および McWafflestix のデータの最初の受け渡しは、Averageの呼び出しでは隠されています。このようなことは小さなリストでは確かに些細なことですが、リストがキャッシュのサイズ、またはワーキングセットを超える場合、これは入札取引になります。

2
dmckee

Robの有益な答えは、Excelを使用して見たものとは完全には一致しないことがわかりました。 Excelと一致させるために、valueListのAverageをStandardDeviation計算に渡しました。

ここに私の2セントがあります...そして、明らかに、関数内のvalueListから移動平均(ma)を計算できますが、standardDeviationを必要とする前に既にたまたま持っています。

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));
}       
1
hongkonggil

拡張メソッドを使用。

using System;
using System.Collections.Generic;

namespace SampleApp
{
    internal class Program
    {
        private static void Main()
        {
            List<double> data = new List<double> {1, 2, 3, 4, 5, 6};

            double mean = data.Mean();
            double variance = data.Variance();
            double sd = data.StandardDeviation();

            Console.WriteLine("Mean: {0}, Variance: {1}, SD: {2}", mean, variance, sd);
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }

    public static class MyListExtensions
    {
        public static double Mean(this List<double> values)
        {
            return values.Count == 0 ? 0 : values.Mean(0, values.Count);
        }

        public static double Mean(this List<double> values, int start, int end)
        {
            double s = 0;

            for (int i = start; i < end; i++)
            {
                s += values[i];
            }

            return s / (end - start);
        }

        public static double Variance(this List<double> values)
        {
            return values.Variance(values.Mean(), 0, values.Count);
        }

        public static double Variance(this List<double> values, double mean)
        {
            return values.Variance(mean, 0, values.Count);
        }

        public static double Variance(this List<double> values, double mean, int start, int end)
        {
            double variance = 0;

            for (int i = start; i < end; i++)
            {
                variance += Math.Pow((values[i] - mean), 2);
            }

            int n = end - start;
            if (start > 0) n -= 1;

            return variance / (n);
        }

        public static double StandardDeviation(this List<double> values)
        {
            return values.Count == 0 ? 0 : values.StandardDeviation(0, values.Count);
        }

        public static double StandardDeviation(this List<double> values, int start, int end)
        {
            double mean = values.Mean(start, end);
            double variance = values.Variance(mean, start, end);

            return Math.Sqrt(variance);
        }
    }
}
1
Rikin Patel
/// <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));
}
0
oleksii

これは人口標準偏差です

private double calculateStdDev(List<double> values)
{
    double average = values.Average();
    return Math.Sqrt((values.Select(val => (val - average) * (val - average)).Sum()) / values.Count);
}

サンプル標準偏差の場合、上記のコードで[values.Count]を[values.Count -1]に変更するだけです。

セットにデータポイントが1つしかないことを確認してください。

0
Amey Vartak

Pythonで統計モジュールを使用できる場合があります。サンプルと母集団の標準偏差をそれぞれ計算するstedev()とpstdev()コマンドがあります。

詳細はこちら: https://www.geeksforgeeks.org/python-statistics-stdev/

st print(st.ptdev(dataframe ['column name']))として統計をインポートします

0
Dhaval

他のすべての答えの問題は、彼らがあなたのデータが大きな配列にあると仮定することです。データがオンザフライで到着する場合、これはより良いアプローチです。このクラスは、データの保存方法や保存方法に関係なく機能します。また、ウォルドルフ法または平方和法の選択も可能です。どちらの方法も、単一のパスを使用して機能します。

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(); }
}
0
MiguelMunoz