Как определить стандартное отклонение (stddev) набора значений? - PullRequest
44 голосов
/ 22 мая 2009

Мне нужно знать, находится ли число по сравнению с набором чисел вне 1 стандартного значения от среднего значения и т. Д.

Ответы [ 12 ]

99 голосов
/ 22 мая 2009

Хотя алгоритм суммирования квадратов в большинстве случаев работает нормально, он может вызвать большие проблемы, если вы имеете дело с очень большими числами. В принципе, вы можете получить отрицательную дисперсию ...

Кроме того, никогда, никогда, никогда не вычисляйте ^ 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));
}

Если у вас есть целое население (в отличие от образца население), тогда используйте return Math.Sqrt(S / (k-1));.

РЕДАКТИРОВАТЬ: Я обновил код в соответствии с замечаниями Джейсона ...

РЕДАКТИРОВАТЬ: Я также обновил код в соответствии с замечаниями Алекса ...

7 голосов
/ 30 октября 2014

в 10 раз быстрее решения, чем у Хайме, но имейте в виду , что, как указал Хайме:

"Хотя алгоритм суммы квадратов работает нормально большую часть времени, он может вызвать большие проблемы, если вы имеете дело с очень большими числами. Вы в основном может привести к отрицательной дисперсии "

Если вы считаете, что имеете дело с очень большими числами или с очень большим количеством чисел, вам следует рассчитывать с использованием обоих методов, если результаты совпадают, вы точно знаете, что можете использовать «мой» метод для вашего случая.

    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;
    }
4 голосов
/ 19 февраля 2016

Библиотека 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 для получения дополнительной информации.

4 голосов
/ 25 декабря 2013

Принятый ответ Хайме великолепен, за исключением того, что вам нужно разделить на k-2 в последней строке (вам нужно разделить на "number_of_elements-1") Еще лучше, начните k в 0:

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));
}
2 голосов
/ 22 мая 2009

Фрагмент кода:

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 голосов
/ 22 мая 2009

Вы можете избежать двух проходов по данным, накапливая среднее и среднеквадратичное значение

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 Подобные вещи, конечно, тривиальны в небольшом списке, но если список превышает размер кеша или даже рабочего набора, это становится предложением о ставке.

1 голос
/ 05 сентября 2014

с методами расширения.

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 голос
/ 25 января 2012

Я обнаружил, что полезный ответ Роба не совсем соответствует тому, что я видел, используя Excel. Чтобы соответствовать Excel, я передал Среднее значение для valueList в расчет StandardDeviation.

Вот мои два цента ... и ясно, что вы можете вычислить скользящее среднее (мА) из valueList внутри функции - но у меня это уже было до того, как потребовалось стандартное отклонение.

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));
}       
0 голосов
/ 28 февраля 2019

Это стандартное отклонение населения

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] в приведенном выше коде.

Убедитесь, что в вашем наборе нет только одной точки данных.

0 голосов
/ 25 октября 2018

Мы можем использовать модуль статистики в Python. Он имеет команды stedev () и pstdev () для вычисления стандартного отклонения выборки и совокупности соответственно.

подробности здесь: https://www.geeksforgeeks.org/python-statistics-stdev/

импортировать статистику как st print (st.ptdev (dataframe ['имя столбца']))

...