使用 LINQ 的标准偏差给出了与迭代计算不同的答案
Standard deviation using LINQ gives different answer from iterative calculations
如果我使用从 this SO question:
稍微修改过的代码对样本进行标准差计算
public double CalculateStandardDeviation(List<double> values, bool sample = false)
{
double mean = 0.0;
double sum = 0.0;
double stdDev = 0.0;
int count = 0;
foreach (double val in values)
{
count++;
double delta = val - mean;
mean += delta / count;
sum += delta * (val - mean);
}
if (1 < count)
stdDev = Math.Sqrt(sum / (count - (sample ? 1 : 0)));
return stdDev;
}
使用这个单元测试:
[Test]
public void Sample_Standard_Deviation_Returns_Expected_Value()
{
//original cite: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
double expected = 2.23606797749979;
double tolerance = 1.0 / System.Math.Pow(10, 13);
var cm = new CommonMath();//a library of math functions we use a lot
List<double> values = new List<double> { 4.0, 2.0, 5.0, 8.0, 6.0 };
double actual = cm.CalculateStandardDeviation(values, true);
Assert.That(actual, Is.EqualTo(expected).Within(tolerance));
}
测试通过,结果值在指定的公差范围内。
但是,如果我使用这个 Linq 化代码,它会失败,返回值 2.5(好像它是总体标准偏差):
double meanOfValues = values.Average();
double sumOfValues = values.Sum();
int countOfValues = values.Count;
double standardDeviationOfValues =
Math.Sqrt(sumOfValues / (countOfValues - (sample ? 1 : 0)));
return standardDeviationOfValues;
由于我从未进行过统计(所以请保持温和),列表中值的 Linq 化(这是一个词)似乎 好像他们应该给我相同的结果,但他们没有,我不明白我做错了什么。 N & N-1 两者的判断动作是一样的,为什么答案不一样呢?
将样本设为假,你会得到相同的答案:2.23606797749979
如果你把样本设为真,你得到 2.5!
因此,您确实需要在两个地方放置相同的 "sample" 值。
让我们从那个开始
values.Sum();
你从
得到的总和
sum += delta * (val - mean);
不一样。
下次您可以从使用 TDD 解决这类问题开始,并以此方式检查每个值。
编辑:Standard Deviation in LINQ
您的 LINQ 版本不计算标准偏差。 Standard Deviation是基于与均值之差的平方和,所以改为:
double meanOfValues = values.Average();
double sumOfValues = values.Select(v => (v-meanOfValues)*(v-meanOfValues)).Sum();
int countOfValues = values.Count;
double standardDeviationOfValues =
Math.Sqrt(sumOfValues / (countOfValues - (sample ? 1 : 0)));
return standardDeviationOfValues;
要遍历值一次,您可以使用 Aggregate
但它并不比普通函数好:
var g = values.Aggregate(new { mean = 0.0, sum = 0.0, count = 0 },
(acc, val) => {
var newcount = acc.count+1;
double delta = val-acc.mean;
var newmean = acc.mean + delta / newcount;
return new { mean = newmean, sum = acc.sum+delta*(val-newmean), count = newcount };
});
var stdDev = Math.Sqrt(g.sum / (g.count - (sample ? 1 : 0)));
如果我使用从 this SO question:
稍微修改过的代码对样本进行标准差计算public double CalculateStandardDeviation(List<double> values, bool sample = false)
{
double mean = 0.0;
double sum = 0.0;
double stdDev = 0.0;
int count = 0;
foreach (double val in values)
{
count++;
double delta = val - mean;
mean += delta / count;
sum += delta * (val - mean);
}
if (1 < count)
stdDev = Math.Sqrt(sum / (count - (sample ? 1 : 0)));
return stdDev;
}
使用这个单元测试:
[Test]
public void Sample_Standard_Deviation_Returns_Expected_Value()
{
//original cite: http://warrenseen.com/blog/2006/03/13/how-to-calculate-standard-deviation/
double expected = 2.23606797749979;
double tolerance = 1.0 / System.Math.Pow(10, 13);
var cm = new CommonMath();//a library of math functions we use a lot
List<double> values = new List<double> { 4.0, 2.0, 5.0, 8.0, 6.0 };
double actual = cm.CalculateStandardDeviation(values, true);
Assert.That(actual, Is.EqualTo(expected).Within(tolerance));
}
测试通过,结果值在指定的公差范围内。
但是,如果我使用这个 Linq 化代码,它会失败,返回值 2.5(好像它是总体标准偏差):
double meanOfValues = values.Average();
double sumOfValues = values.Sum();
int countOfValues = values.Count;
double standardDeviationOfValues =
Math.Sqrt(sumOfValues / (countOfValues - (sample ? 1 : 0)));
return standardDeviationOfValues;
由于我从未进行过统计(所以请保持温和),列表中值的 Linq 化(这是一个词)似乎 好像他们应该给我相同的结果,但他们没有,我不明白我做错了什么。 N & N-1 两者的判断动作是一样的,为什么答案不一样呢?
将样本设为假,你会得到相同的答案:2.23606797749979 如果你把样本设为真,你得到 2.5!
因此,您确实需要在两个地方放置相同的 "sample" 值。
让我们从那个开始
values.Sum();
你从
得到的总和sum += delta * (val - mean);
不一样。
下次您可以从使用 TDD 解决这类问题开始,并以此方式检查每个值。
编辑:Standard Deviation in LINQ
您的 LINQ 版本不计算标准偏差。 Standard Deviation是基于与均值之差的平方和,所以改为:
double meanOfValues = values.Average();
double sumOfValues = values.Select(v => (v-meanOfValues)*(v-meanOfValues)).Sum();
int countOfValues = values.Count;
double standardDeviationOfValues =
Math.Sqrt(sumOfValues / (countOfValues - (sample ? 1 : 0)));
return standardDeviationOfValues;
要遍历值一次,您可以使用 Aggregate
但它并不比普通函数好:
var g = values.Aggregate(new { mean = 0.0, sum = 0.0, count = 0 },
(acc, val) => {
var newcount = acc.count+1;
double delta = val-acc.mean;
var newmean = acc.mean + delta / newcount;
return new { mean = newmean, sum = acc.sum+delta*(val-newmean), count = newcount };
});
var stdDev = Math.Sqrt(g.sum / (g.count - (sample ? 1 : 0)));