Подтвердить что ты не робот

Стандартное отклонение общего списка?

Мне нужно рассчитать стандартное отклонение общего списка. Я попытаюсь включить мой код. Его общий список с данными в нем. Данные в основном представляют собой float и ints. Вот мой код, который относительно этого, не вдаваясь в подробности:

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. Я знаю, как сделать это из списка парных, но не списка общего списка данных. Если у кого-то есть опыт в этом, пожалуйста, помогите.

4b9b3361

Ответ 1

Эта статья должна вам помочь. Он создает функцию, которая вычисляет отклонение последовательности значений double. Все, что вам нужно сделать, это предоставить последовательность соответствующих элементов данных.

Результирующая функция:

private double CalculateStdDev(IEnumerable<double> values)
{   
  double ret = 0;
  if (values.Count() > 0) 
  {      
     //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      
     ret = Math.Sqrt((sum) / (values.Count()-1));   
  }   
  return ret;
}

Это достаточно легко адаптировать для любого общего типа, если мы предоставляем селектор для вычисляемого значения. LINQ отлично подходит для этого, Select funciton позволяет проецировать из вашего общего списка пользовательских типов последовательность числовых значений, для которых можно вычислить стандартное отклонение:

List<ValveData> list = ...
var result = list.Select( v => (double)v.SomeField )
                 .CalculateStdDev();

Ответ 2

Приведенный выше пример немного неверен и может иметь деление на нулевую ошибку, если ваш набор населения равен 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)));
    }
}

Ответ 3

Несмотря на то, что принятый ответ кажется математически правильным, он неверен с точки зрения программирования - он перечисляет одну и ту же последовательность 4 раза. Это может быть нормально, если базовый объект является списком или массивом, но если вход представляет собой отфильтрованное/агрегированное выражение /etc linq, или если данные поступают непосредственно из базы данных или сетевого потока, это приведет к значительно более низкой производительности.

Я бы очень рекомендовал не изобретать колесо и использовать одну из лучших математических библиотек с открытым исходным кодом Math.NET. Мы использовали эту библиотеку в нашей компании и очень довольны производительностью.

PM > Install-Package 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

Ответ 4

Я вижу, что вы делаете, и я использую нечто подобное. Мне кажется, что вы недостаточно далеко. Я склонен инкапсулировать всю обработку данных в один класс, таким образом, я могу кэшировать значения, которые вычисляются до тех пор, пока список не изменится. например:

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

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

Кроме того, поскольку среднее значение используется в алгоритме стандартного отклонения, вычисление стандартного отклонения сначала даст нам среднее значение бесплатно, а вычисление среднего значения вначале даст нам небольшое повышение производительности в расчете стандартного отклонения, предполагая мы не забыли проверить флаг.

Кроме того! такие места, как средняя функция, где вы все равно зацикливаете любое значение, - это отличное время для кэширования таких вещей, как минимальные и максимальные значения. Разумеется, запросы на эту информацию должны сначала проверить, были ли они кэшированы, и что может привести к относительной замедлению по сравнению с просто обнаружением max, используя список, поскольку он выполняет всю дополнительную работу по настройке всех соответствующих кэшей, а не только один ваш доступ.