2010-06-29 4 views
45

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

ответ

48

This article должен помочь вам. Он создает функцию, которая вычисляет отклонение последовательности значений 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(); 
+0

У моего C# нет СРЕДНЕГО. Он не появляется. Это одна из моих проблем. Также я не могу передать общий список через мою функцию в качестве параметров. Средство должно быть реализовано внутри stdev-метода, как мой код выше. Мое стандартное отклонение отключено. –

+0

Также ребята. C# не имеет среднего (Math.average). Поэтому я рассчитываю, что я сам, как мой код выше. Это стандартное отклонение, с которым у меня больше всего неприятностей. Спасибо –

+1

@Tom Hangler, убедитесь, что вы добавили 'using System.Linq;' в верхней части вашего файла, чтобы включить библиотеку функций LINQ. Сюда входят как «Средние()», так и «Select()» – LBushkin

125

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

+1 для простоты –

+1

Этот вопрос должен быть ответом, он вычисляет стандартное отклонение в отличие от ответа Л.Бушкина, который действительно вычисляет стандартное отклонение образца. – Wouter

+0

Престижность также для простоты. Красиво сделано. – PseudoToad

17

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

0

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

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

Смежные вопросы