2010-06-29 21 views
45

Devo calcolare la deviazione standard di un elenco generico. Cercherò di includere il mio codice. È un elenco generico con i dati in esso contenuti. I dati sono per lo più float e int. Ecco il mio codice che è relativo ad esso, senza entrare in al maggior numero di dettagli:Deviazione standard dell'elenco generico?

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

Ecco la funzione in cui la deviazione standard deve essere calcolato:

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

     } 
    } 
} 

Ignora che cosa è all'interno della LatchStdev() funzione perché sono sicuro che non è giusto. È solo il mio povero tentativo di calcolare il dev dev. So come farlo da una lista di doppi, ma non da una lista di liste di dati generici. Se qualcuno ha esperienza in questo, per favore aiutatemi.

risposta

48

This article dovrebbe aiutarti. Crea una funzione che calcola la deviazione di una sequenza di valori double. Tutto ciò che devi fare è fornire una sequenza di dati appropriati.

La funzione risultante è:

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

Questo è abbastanza facile da adattare ad ogni tipo generico, purché fornendo un selettore per il valore essendo calcolato. LINQ è grande per questo, il funciton Select consente di proiettare dal tuo elenco generico di tipi personalizzati una sequenza di valori numerici per i quali calcolare la deviazione standard:

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

il mio C# non ha un MEDIA. Non si presenta. Questo è uno dei miei problemi. Inoltre non posso passare una lista generica attraverso la mia funzione come parametro. La media deve essere implementata all'interno di stdevmethod come il mio codice sopra. La mia deviazione standard è al di là di questo. –

+0

Anche ragazzi. C# non ha la media (Math.average). Quindi calcolo il significato come il mio codice sopra. È la deviazione standard con cui ho più problemi. Grazie –

+1

@Tom Hangler, assicurati di aver aggiunto 'utilizzando System.Linq;' nella parte superiore del file per includere la libreria delle funzioni LINQ. Questi includono sia 'Media()' che 'Seleziona()' – LBushkin

125

L'esempio precedente è leggermente sbagliata e potrebbe avere un dividi per errore zero se la tua popolazione impostata è 1. Il seguente codice è in qualche modo più semplice e dà il risultato della "deviazione standard della popolazione". (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 per semplicità –

+1

Questa dovrebbe essere la risposta, calcola la Deviazione standard in opposizione alla risposta di LBushkin che calcola veramente la Deviazione Standard campione – Wouter

+0

Complimenti per semplicità. Ben fatto. – PseudoToad

17

Anche se la risposta accettata sembra matematicamente corretto, è sbagliato dal punto di vista di programmazione - si enumera la stessa sequenza di 4 volte. Questo potrebbe essere ok se l'oggetto sottostante è un elenco o un array, ma se l'input è un'espressione filtrata/aggregata/etc linq, o se i dati provengono direttamente dal database o dal flusso di rete, ciò causerebbe prestazioni molto inferiori.

Consiglio vivamente di non reinventare la rotella e utilizzare una delle migliori librerie matematiche open source Math.NET. Abbiamo usato quella lib nella nostra azienda e siamo molto contenti della performance.

PM> Installa-Package MathNet.Numerics

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

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

Vedere http://numerics.mathdotnet.com/docs/DescriptiveStatistics.html per ulteriori informazioni.

Infine, per coloro che vogliono ottenere il risultato più veloce possibile e sacrificare un po 'di precisione, leggere algoritmo "in un solo passaggio" https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods

0

vedo quello che stai facendo, e io uso qualcosa di simile. Mi sembra che tu non stia andando abbastanza lontano. Tendo a incapsulare tutta l'elaborazione dei dati in una singola classe, in questo modo posso memorizzare nella cache i valori che vengono calcolati finché la lista non cambia. per esempio:

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

Si noterà che con questo metodo, solo la prima richiesta di medio effettivamente calcola la media. Dopodiché, finché non aggiungiamo (o rimuoviamo o modifichiamo del tutto, ma non vengono mostrati quelli) dall'elenco, possiamo ottenere la media praticamente nulla.

Inoltre, poiché la media è utilizzata nell'algoritmo per la deviazione standard, calcolare prima la deviazione standard ci darà la media gratuitamente, e calcolare la media per primo ci darà un piccolo incremento di prestazioni nel calcolo della deviazione standard, supponendo che ricordiamo di controllare la bandiera.

Inoltre! luoghi come la funzione media, in cui si sta già eseguendo il looping di ogni valore, è un ottimo momento per memorizzare dati come i valori minimo e massimo. Naturalmente, le richieste di queste informazioni devono prima verificare se sono state memorizzate nella cache, e ciò può causare un rallentamento relativo rispetto al solo trovare il massimo usando la lista, poiché fa tutto il lavoro extra che imposta tutte le cache in questione, non solo il uno tuo accesso.

Problemi correlati