2009-05-22 12 views
42

मुझे पता है कि अगर एक नंबर संख्याओं के एक समूह की तुलना में मतलब, आदि से 1 stddev के बाहर है की जरूरत है ..मैं मूल्यों के एक सेट के मानक विचलन (stddev) को कैसे निर्धारित करूं?

+3

यह होमवर्क टैग लापता होने लगता है .... – overslacked

+12

कृपया कृपया कृपया कृपया ओपी, होमवर्क प्रयोजनों के लिए एक सवाल पूछ रहा है के बजाय एक "वास्तविक" परियोजना के लिए या आत्म-सुधार के लिए यह न मानें । उनसे पूछों। –

+3

मैं वास्तव में होमवर्क कारणों से नहीं पूछ रहा हूं, लेकिन अगर यह उन लोगों की मदद करता है जो उत्तर खोजने के लिए होमवर्क कर रहे हैं, तो कृपया –

उत्तर

94

वर्गों एल्गोरिथ्म का योग ठीक समय के सबसे अधिक काम करता है, यह बहुत बड़ी मुसीबत पैदा कर सकता है अगर आप बहुत बड़ी संख्या के साथ काम कर रहे हैं। आप मूल रूप से एक नकारात्मक भिन्नता के साथ समाप्त हो सकते हैं ...

प्लस, कभी भी कभी नहीं, कभी भी^2 को पाउ (ए, 2) के रूप में गणना करें, ए * ए लगभग निश्चित रूप से तेज़ है।

मानक विचलन की गणना करने का अब तक का सबसे अच्छा तरीका Welford's method है। मेरे सी बहुत जंग लगी है, लेकिन यह कुछ ऐसा दिखाई दे सकता है: आप पूरे आबादी है (के रूप में एक नमूना आबादी के खिलाफ) हैं

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)); का उपयोग करें।

संपादित करें: मैं जेसन की टिप्पणी के अनुसार कोड को नवीनीकृत किया है ...

संपादित करें: मैं भी एलेक्स की टिप्पणी के अनुसार कोड को नवीनीकृत किया है ...

+2

+1: मैंने इस पर न्यूथ की टिप्पणी पढ़ी है लेकिन कभी नहीं पता कि इसे वेलफोर्ड की विधि कहा जाता है। एफवाईआई आप के == 1 मामले को खत्म कर सकते हैं, यह सिर्फ काम करता है। –

+2

ओएच: और आप अंत में विभाजित-द्वारा-एन या विभाजित-द्वारा-एन -1 भूल रहे हैं। –

+7

अब देखें कि आपने क्या किया है। आपने मुझे कुछ नया सीखने के लिए दिया है। तुम जानवर हो। – dmckee

2

आप मतलब अर्जित होने के कारण डेटा पर दो गुजरता करने से बचने और मतलब वर्ग

कर सकते हैं
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) का एक कारक अक्सर साथ ही उचित है।

बीटीडब्ल्यू - Demi और McWafflestix में डेटा पर पहला पास Average पर कॉल में छिपा हुआ है। उस तरह की चीज एक छोटी सूची पर निश्चित रूप से तुच्छ है, लेकिन यदि सूची कैश के आकार से अधिक हो या यहां तक ​​कि कामकाजी सेट भी हो, तो यह एक बोली सौदा हो जाता है।

+1

आपका सूत्र गलत है। यह सिग्मा = sqrt (meanqr - mean^2) इस पृष्ठ को http://en.wikipedia.org/wiki/Standard_deviation सावधानीपूर्वक अपनी गलती देखने के लिए पढ़ें। – leif

+0

@leif: हाँ। और मुझे भी आयामी समस्या का ध्यान रखना चाहिए था। – dmckee

+0

-1: गणितीय रूप से सही, लेकिन संख्यात्मक रूप से यह बुरा है। –

2

कोड स्निपेट:

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

गणना - 1 या गणना द्वारा विभाजित इस बात पर निर्भर करता है कि क्या हम पूरी आबादी या नमूना के बारे में बात कर रहे हैं, हां? ऐसा लगता है कि ओपी एक ज्ञात आबादी के बारे में बात कर रहा है लेकिन पूरी तरह स्पष्ट नहीं है। –

+0

यह सही है - यह नमूना भिन्नता के लिए है। मैं हाइलाइट की सराहना करता हूं। – Demi

+0

आपका कोड एक मूल्य के साथ एक सूची के वैध मामले के लिए दुर्घटनाग्रस्त हो जाता है। नमूना stddev के लिए – SPWorley

0
/// <summary> 
/// Calculates standard deviation, same as MATLAB std(X,0) function 
/// <seealso cref="http://www.mathworks.co.uk/help/techdoc/ref/std.html"/> 
/// </summary> 
/// <param name="values">enumumerable data</param> 
/// <returns>Standard deviation</returns> 
public static double GetStandardDeviation(this IEnumerable<double> values) 
{ 
    //validation 
    if (values == null) 
     throw new ArgumentNullException(); 

    int lenght = values.Count(); 

    //saves from devision by 0 
    if (lenght == 0 || lenght == 1) 
     return 0; 

    double sum = 0.0, sum2 = 0.0; 

    for (int i = 0; i < lenght; i++) 
    { 
     double item = values.ElementAt(i); 
     sum += item; 
     sum2 += item * item; 
    } 

    return Math.Sqrt((sum2 - sum * sum/lenght)/(lenght - 1)); 
} 
1

मैंने पाया कि रोब का सहायक जवाब एक्सेल का उपयोग करके जो देख रहा था उससे काफी मेल नहीं खाता था। एक्सेल से मिलान करने के लिए, मैंने मानक डिवीजन गणना में मानसूची के लिए औसत पारित किया।

यहां मेरे दो सेंट हैं ... और स्पष्ट रूप से आप फ़ंक्शन के अंदर मूल्य सूची से चलती औसत (एम) की गणना कर सकते हैं - लेकिन मुझे पहले से ही मानक विचलन की आवश्यकता होती है। को छोड़कर आप ("number_of_elements -1" से आप विभाजित करने की आवश्यकता) अंतिम पंक्ति में कश्मीर -2 द्वारा विभाजित करने की आवश्यकता

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

जैमे द्वारा स्वीकार कर लिया जवाब है, बहुत अच्छा है। अभी तक बेहतर, 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)); 
} 
1
विस्तार तरीकों के साथ

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

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

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 देखें।

0

अन्य सभी उत्तरों के साथ समस्या यह है कि वे मानते हैं कि आपके पास डेटा एक बड़ी सरणी में है। यदि आपका डेटा मक्खी पर आ रहा है, तो यह एक बेहतर दृष्टिकोण होगा। इस वर्ग पर ध्यान दिए बिना कि आप अपना डेटा कैसे स्टोर करते हैं या नहीं। यह आपको वाल्डोर्फ विधि या योग-वर्ग-वर्ग विधि का विकल्प भी देता है। दोनों विधियां एक ही पास का उपयोग कर काम करती हैं।

public final class StatMeasure { 
    private StatMeasure() {} 

    public interface Stats1D { 

    /** Add a value to the population */ 
    void addValue(double value); 

    /** Get the mean of all the added values */ 
    double getMean(); 

    /** Get the standard deviation from a sample of the population. */ 
    double getStDevSample(); 

    /** Gets the standard deviation for the entire population. */ 
    double getStDevPopulation(); 
    } 

    private static class WaldorfPopulation implements Stats1D { 
    private double mean = 0.0; 
    private double sSum = 0.0; 
    private int count = 0; 

    @Override 
    public void addValue(double value) { 
     double tmpMean = mean; 
     double delta = value - tmpMean; 
     mean += delta/++count; 
     sSum += delta * (value - mean); 
    } 

    @Override 
    public double getMean() { return mean; } 

    @Override 
    public double getStDevSample() { return Math.sqrt(sSum/(count - 1)); } 

    @Override 
    public double getStDevPopulation() { return Math.sqrt(sSum/(count)); } 
    } 

    private static class StandardPopulation implements Stats1D { 
    private double sum = 0.0; 
    private double sumOfSquares = 0.0; 
    private int count = 0; 

    @Override 
    public void addValue(double value) { 
     sum += value; 
     sumOfSquares += value * value; 
     count++; 
    } 

    @Override 
    public double getMean() { return sum/count; } 

    @Override 
    public double getStDevSample() { 
     return (float) Math.sqrt((sumOfSquares - ((sum * sum)/count))/(count - 1)); 
    } 

    @Override 
    public double getStDevPopulation() { 
     return (float) Math.sqrt((sumOfSquares - ((sum * sum)/count))/count); 
    } 
    } 

    /** 
    * Returns a way to measure a population of data using Waldorf's method. 
    * This method is better if your population or values are so large that 
    * the sum of x-squared may overflow. It's also probably faster if you 
    * need to recalculate the mean and standard deviation continuously, 
    * for example, if you are continually updating a graphic of the data as 
    * it flows in. 
    * 
    * @return A Stats1D object that uses Waldorf's method. 
    */ 
    public static Stats1D getWaldorfStats() { return new WaldorfPopulation(); } 

    /** 
    * Return a way to measure the population of data using the sum-of-squares 
    * method. This is probably faster than Waldorf's method, but runs the 
    * risk of data overflow. 
    * 
    * @return A Stats1D object that uses the sum-of-squares method 
    */ 
    public static Stats1D getSumOfSquaresStats() { return new StandardPopulation(); } 
} 
संबंधित मुद्दे