LINQ क्या कुल एसक्यूएल फ़ंक्शन STDDEV()
(मानक विचलन) को मॉडल करता है ?
यदि नहीं, तो इसकी गणना करने का सबसे सरल / सर्वोत्तम तरीका क्या है?
उदाहरण:
SELECT test_id, AVERAGE(result) avg, STDDEV(result) std
FROM tests
GROUP BY test_id
LINQ क्या कुल एसक्यूएल फ़ंक्शन STDDEV()
(मानक विचलन) को मॉडल करता है ?
यदि नहीं, तो इसकी गणना करने का सबसे सरल / सर्वोत्तम तरीका क्या है?
उदाहरण:
SELECT test_id, AVERAGE(result) avg, STDDEV(result) std
FROM tests
GROUP BY test_id
जवाबों:
आप अपने खुद के विस्तार की गणना कर सकते हैं
public static class Extensions
{
public static double StdDev(this IEnumerable<double> values)
{
double ret = 0;
int count = values.Count();
if (count > 1)
{
//Compute the Average
double avg = values.Average();
//Perform the Sum of (value-avg)^2
double sum = values.Sum(d => (d - avg) * (d - avg));
//Put it all together
ret = Math.Sqrt(sum / count);
}
return ret;
}
}
यदि आपके पास पूरी आबादी के बजाय आबादी का एक नमूना है, तो आपको उपयोग करना चाहिए ret = Math.Sqrt(sum / (count - 1));
।
क्रिस बेनेट द्वारा LINQ में मानक विचलन जोड़ने से विस्तार में परिवर्तित ।
stdev = g.Select(o => o.number).StdDev()
।
डायनेमी का उत्तर काम करता है लेकिन परिणाम प्राप्त करने के लिए डेटा से कई गुजरता है। यह एकल पास विधि है जो नमूना मानक विचलन की गणना करती है :
public static double StdDev(this IEnumerable<double> values)
{
// ref: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
double mean = 0.0;
double sum = 0.0;
double stdDev = 0.0;
int n = 0;
foreach (double val in values)
{
n++;
double delta = val - mean;
mean += delta / n;
sum += delta * (val - mean);
}
if (1 < n)
stdDev = Math.Sqrt(sum / (n - 1));
return stdDev;
}
यह नमूना मानक विचलन है क्योंकि यह विभाजित होता है n - 1
। सामान्य मानक विचलन के लिए आपको n
इसके बजाय विभाजित करने की आवश्यकता होती है ।
यह Welford की विधि का उपयोग करता है जिसमें विधि की तुलना में उच्च संख्यात्मक सटीकता है Average(x^2)-Average(x)^2
।
this IEnumerable<double?> values
और val in values.Where(val => val != null)
। इसके अलावा, मैं ध्यान दूंगा कि यह विधि (Welford का तरीका) ऊपर की विधि से अधिक सटीक और तेज है।
यह डेविड क्लार्क के उत्तर को एक ऐसे विस्तार में परिवर्तित करता है जो अन्य एग्रीगेट LINQ फ़ंक्शंस की तरह ही फॉर्म का अनुसरण करता है।
उपयोग होगा: var stdev = data.StdDev(o => o.number)
public static class Extensions
{
public static double StdDev<T>(this IEnumerable<T> list, Func<T, double> values)
{
// ref: /programming/2253874/linq-equivalent-for-standard-deviation
// ref: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
var mean = 0.0;
var sum = 0.0;
var stdDev = 0.0;
var n = 0;
foreach (var value in list.Select(values))
{
n++;
var delta = value - mean;
mean += delta / n;
sum += delta * (value - mean);
}
if (1 < n)
stdDev = Math.Sqrt(sum / (n - 1));
return stdDev;
}
}
Average
/ Min
/ Max
/ etc का चयनकर्ता कार्यों के साथ और बिना ओवरलोड है। उनके पास अभिन्न प्रकार, फ्लोट आदि के लिए ओवरलोड भी हैं
सीधे बिंदु पर (और C #> 6.0), डायनामिस का उत्तर यह बन जाता है:
public static double StdDev(this IEnumerable<double> values)
{
var count = values?.Count() ?? 0;
if (count <= 1) return 0;
var avg = values.Average();
var sum = values.Sum(d => Math.Pow(d - avg, 2));
return Math.Sqrt(sum / count);
}
संपादित करें 2020-08-27:
मैंने कुछ प्रदर्शन परीक्षण करने के लिए @ डेविड क्लार्क की टिप्पणियाँ लीं और यह परिणाम हैं:
public static (double stdDev, double avg) StdDevFast(this List<double> values)
{
var count = values?.Count ?? 0;
if (count <= 1) return (0, 0);
var avg = GetAverage(values);
var sum = GetSumOfSquareDiff(values, avg);
return (Math.Sqrt(sum / count), avg);
}
private static double GetAverage(List<double> values)
{
double sum = 0.0;
for (int i = 0; i < values.Count; i++)
sum += values[i];
return sum / values.Count;
}
private static double GetSumOfSquareDiff(List<double> values, double avg)
{
double sum = 0.0;
for (int i = 0; i < values.Count; i++)
{
var diff = values[i] - avg;
sum += diff * diff;
}
return sum;
}
मैंने इसे एक मिलियन रैंडम डबल्स
की एक सूची के साथ परीक्षण किया था मूल कार्यान्वयन में ~ 48ms
का रनटाइम था प्रदर्शन को अनुकूलित कार्यान्वयन 2-3ms
तो यह एक महत्वपूर्ण सुधार है।
कुछ दिलचस्प विवरण:
Math.Pow से छुटकारा पाने से 33ms की वृद्धि होती है!
IEnumerable 6ms की बजाय
मैन्युअल रूप से सूची करें। औसत गणना 4ms
फॉर-लूप के बजाय फॉरेस्ट-लूप्स 2ms
एरे के बजाय लिस्ट में केवल ~ 2% का सुधार लाता है इसलिए मैंने इसे
डबल के बजाय सिंगल का उपयोग करके छोड़ दिया है।
इसके अलावा कोड को कम करना और गोटो (हाँ गोटो ... 90 के दशक के बाद से इसका इस्तेमाल नहीं किया है ...) के बजाय-छोरों के लिए भुगतान नहीं करता है, धन्यवाद!
मैंने समानांतर गणना का भी परीक्षण किया है, यह सूची> 200.000 वस्तुओं पर समझ में आता है। ऐसा लगता है कि हार्डवेयर और सॉफ्टवेयर को बहुत अधिक प्रारंभिक करने की आवश्यकता है और यह छोटी सूची के लिए है जो उत्पादक-उत्पादक है।
वार्मअप-टाइम से छुटकारा पाने के लिए सभी परीक्षणों को लगातार दो बार निष्पादित किया गया।
Count()
, Average()
और Sum()
। यह छोटे मूल्यों के लिए ठीक है, count
लेकिन अगर प्रदर्शन count
बड़ा है, तो प्रदर्शन को प्रभावित करने की क्षमता है।
(this IList<double> values)
, प्रदर्शन परीक्षण प्रभाव दिखाएगा, और कितने आइटम एक महत्वपूर्ण अंतर बनाते हैं
Count
, Average
, Sum
) प्रत्येक पुनरावृति संग्रह ताकि आप अभी भी तीन पूर्ण पुनरावृत्तियों एक परिणाम का उत्पादन किया है।
public static double StdDev(this IEnumerable<int> values, bool as_sample = false)
{
var count = values.Count();
if (count > 0) // check for divide by zero
// Get the mean.
double mean = values.Sum() / count;
// Get the sum of the squares of the differences
// between the values and the mean.
var squares_query =
from int value in values
select (value - mean) * (value - mean);
double sum_of_squares = squares_query.Sum();
return Math.Sqrt(sum_of_squares / (count - (as_sample ? 1 : 0)))
}
count
।
सरल 4 लाइनों, मैंने डबल्स की एक सूची का उपयोग किया लेकिन एक का उपयोग कर सकता है IEnumerable<int> values
public static double GetStandardDeviation(List<double> values)
{
double avg = values.Average();
double sum = values.Sum(v => (v - avg) * (v - avg));
double denominator = values.Count - 1;
return denominator > 0.0 ? Math.Sqrt(sum / denominator) : -1;
}