2010-06-29 12 views
45

Potrzebuję obliczyć odchylenie standardowe listy ogólnej. Spróbuję dołączyć mój kod. Jest to ogólna lista zawierająca dane. Dane to głównie floats i ints. Tu jest mój kod, który jest w stosunku do niej bez dostania się do większych szczegółach:Odchylenie standardowe listy ogólnej?

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

Oto funkcja, gdzie potrzebuje odchylenie standardowe oblicza się:

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

     } 
    } 
} 

Ignoruj ​​co jest wewnątrz LatchStdev() Funkcja, ponieważ jestem pewien, że to nie jest w porządku. To tylko moja słaba próba obliczenia st dev. Wiem, jak to zrobić z listą dubli, ale nie z listą ogólnej listy danych. Jeśli ktoś ma w tym doświadczenie, proszę o pomoc.

Odpowiedz

48

This article powinien ci pomóc. Tworzy funkcję, która oblicza odchylenie sekwencji wartości double. Wszystko, co musisz zrobić, to dostarczyć sekwencję odpowiednich elementów danych.

Funkcja wynikające brzmi:

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

Jest to dość łatwe do dostosowania do każdego typu rodzajowego, tak długo, jak zapewniamy selektor dla wartości są obliczane. LINQ jest idealne dla tym, Select funciton pozwala wystawać z rodzajowego listy typów niestandardowych sekwencję wartości numerycznych, dla których obliczyć odchylenie standardowe:

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

my C# nie ma ŚREDNIEJ. To się nie pokazuje. To jeden z moich problemów. Nie mogę również przekazać ogólnej listy przez moją funkcję jako parametry. Średnia musi być zaimplementowana wewnątrz stdevmethod jak mój kod powyżej. Moje odchylenie standardowe jest poza tym. –

+0

Również faceci. C# nie ma średniej (Math.average). Więc obliczam średnią, tak jak mój kod powyżej. Jest to standardowe odchylenie, z którym mam najwięcej problemów. Dzięki –

+1

@ Tom Hangler, upewnij się, że dodajesz 'using System.Linq;' na górze twojego pliku, aby dołączyć bibliotekę funkcji LINQ. THese obejmują zarówno 'Average()', jak i 'Select()' – LBushkin

125

Powyższy przykład jest nieco błędne i może mieć podziel przez zero błędu, jeśli twoja populacja ma wartość 1. Poniższy kod jest nieco prostszy i daje "odchylenie standardowe populacji". (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 dla prostoty –

+1

Ten powinien być odpowiedzią, oblicza odchylenie standardowe w przeciwieństwie do odpowiedzi LBushkina, która oblicza standardowe odchylenie standardowe – Wouter

+0

również dla uproszczenia. Ładnie wykonane. – PseudoToad

17

Choć akceptowane Odpowiedź wydaje matematycznie poprawne, to jest błędne z punktu widzenia programowania - to wylicza taką samą sekwencję 4 razy. Może to być ok, jeśli bazowym obiektem jest lista lub tablica, ale jeśli dane wejściowe jest filtrowanym/zagregowanym/etc linq expression, lub jeśli dane pochodzą bezpośrednio z bazy danych lub strumienia sieciowego, spowodowałoby to znacznie niższą wydajność.

Gorąco polecam, aby nie wymyślać koła i korzystać z jednej z lepszych bibliotek matematycznych Open Source Math.NET. Używamy tej biblioteki w naszej firmie i jesteśmy bardzo zadowoleni z jej wydajności.

PM> Instaluj-Pakiet MathNet.Numerics

var populationStdDev = new List<double>(1d, 2d, 3d, 4d, 5d).PopulationStandardDeviation(); 

var sampleStdDev = new List<double>(2d, 3d, 4d).StandardDeviation(); 

Zobacz http://numerics.mathdotnet.com/docs/DescriptiveStatistics.html aby uzyskać więcej informacji.

Wreszcie dla tych, którzy chcą dostać najszybszy możliwy wynik i poświęcić trochę precyzji, czytać algorytm „one-pass” https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods

0

widzę, co robisz, i używam czegoś podobnego. Wydaje mi się, że nie idziesz wystarczająco daleko. Mam tendencję do enkapsulacji całego przetwarzania danych do jednej klasy, w ten sposób mogę buforować wartości, które są obliczane, aż lista się zmieni. na przykład:

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

Zauważysz, że za pomocą tej metody, tylko pierwszy wniosek o średni rzeczywiście oblicza średnią. Po tym, o ile nie dodamy (ani nie usuwamy, ani nie modyfikujemy w ogóle, ale te, które pokazano) czegoś z listy, możemy uzyskać średnią za praktycznie nic. Dodatkowo, ponieważ średnia jest wykorzystywana w algorytmie dla odchylenia standardowego, obliczenie odchylenia standardowego najpierw da nam średnią za darmo, a obliczenie średniej pierwszej da nam niewielki wzrost wydajności w standardowych obliczeniach obliczeniowych, zakładając, że pamiętamy, aby sprawdzić flagę.

Co więcej! Miejsca takie jak średnia funkcja, w której i tak przechodzisz przez wszystkie wartości, to świetny czas, aby cache rzeczy takie jak wartości minimalne i maksymalne. Oczywiście, prośby o tę informację muszą najpierw sprawdzić, czy zostały zbuforowane, i które mogą spowodować względne spowolnienie w porównaniu do znalezienia maksimum przy użyciu listy, ponieważ wykonuje ona wszystkie dodatkowe prace konfigurując wszystkie odpowiednie pamięci podręczne, a nie tylko jeden twój dostęp.

Powiązane problemy