使用Boost从C ++中的样本向量计算平均值和标准偏差
有没有办法使用Boost来计算包含样本的vector的均值和标准偏差?
或者我必须创build一个累加器,并将其载入它?
使用累加器是计算Boost中平均值和标准差的方法。
accumulator_set<double, stats<tag::variance> > acc; for_each(a_vec.begin(), a_vec.end(), bind<void>(ref(acc), _1)); cout << mean(acc) << endl; cout << sqrt(variance(acc)) << endl;
我不知道Boost是否有更具体的function,但是你可以用标准库来做。
给定std::vector<double> v
,这是一个天真的方式:
#include <numeric> double sum = std::accumulate(v.begin(), v.end(), 0.0); double mean = sum / v.size(); double sq_sum = std::inner_product(v.begin(), v.end(), v.begin(), 0.0); double stdev = std::sqrt(sq_sum / v.size() - mean * mean);
对于巨大或微小的值,这易受上溢或下溢的影响。 计算标准偏差的一个更好的方法是:
double sum = std::accumulate(v.begin(), v.end(), 0.0); double mean = sum / v.size(); std::vector<double> diff(v.size()); std::transform(v.begin(), v.end(), diff.begin(), std::bind2nd(std::minus<double>(), mean)); double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); double stdev = std::sqrt(sq_sum / v.size());
更新为C + + 11:
对std::transform
的调用可以使用lambda函数而不是std::minus
和std::bind2nd
(现在不赞成使用)来编写:
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
如果性能对你很重要,并且你的编译器支持lambdaexpression式,stdev计算可以更快,更简单:在VS 2012的testing中,我发现下面的代码比select的答案中给出的Boost代码快10倍以上; 它比使用musiphil提供的标准库的答案更安全的版本也快5倍。
注意我正在使用样本标准偏差,所以下面的代码给出了稍微不同的结果( 为什么在标准偏差中有一个Minus One )
double sum = std::accumulate(std::begin(v), std::end(v), 0.0); double m = sum / v.size(); double accum = 0.0; std::for_each (std::begin(v), std::end(v), [&](const double d) { accum += (d - m) * (d - m); }); double stdev = sqrt(accum / (v.size()-1));
我的答案与Josh Greifer类似,但推广到样本协方差。 样本方差只是样本协方差,但两个input相同。 这包括贝塞尔的相关性。
template <class Iter> typename Iter::value_type cov(const Iter &x, const Iter &y) { double sum_x = std::accumulate(std::begin(x), std::end(x), 0.0); double sum_y = std::accumulate(std::begin(y), std::end(y), 0.0); double mx = sum_x / x.size(); double my = sum_y / y.size(); double accum = 0.0; for (auto i = 0; i < x.size(); i++) { accum += (x.at(i) - mx) * (y.at(i) - my); } return accum / (x.size() - 1); }
创build您自己的容器:
template <class T> class statList : public std::list<T> { public: statList() : std::list<T>::list() {} ~statList() {} T mean() { return accumulate(begin(),end(),0.0)/size(); } T stddev() { T diff_sum = 0; T m = mean(); for(iterator it= begin(); it != end(); ++it) diff_sum += ((*it - m)*(*it -m)); return diff_sum/size(); } };
它确实有一些限制,但是当你知道你在做什么的时候,它会很好地工作。
比前面提到的版本快两倍 – 主要是因为transform()和inner_product()循环被join。 对不起,我的快捷方式/ typedefs /macros:Flo =浮动。 Cit =常量迭代。 CR常量参考 VFlo – 向量。 在VS2010testing
Flo stdDev2(VFlo CR crVec) { SZ n = crVec.size(); if (n < 2) return 0.0f; Flo fSqSum = 0.0f, fSum = 0.0f; Cit(VFlo, crVec) { Flo f = *cx; fSqSum += f * f; fSum += f; } Flo fSumSq = fSum * fSum; Flo fSumSqDivN = fSumSq / n; Flo fSubSqSum = fSqSum - fSumSqDivN; Flo preSqrt = fSubSqSum / (n-1); return sqrt(preSqrt); }
//表示c ++中的偏差
/ 观测值与感兴趣量的真值(如总体平均值)之间的差异是一个误差,是一个偏差,即观测值与真实值估计之间的差值(例如一个估计可能是一个样本均值)是一个残差。 这些概念适用于测量间隔和比率级别的数据。 /
#include <iostream> #include <conio.h> using namespace std; /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char** argv) { int i,cnt; cout<<"please inter count:\t"; cin>>cnt; float *num=new float [cnt]; float *s=new float [cnt]; float sum=0,ave,M,M_D; for(i=0;i<cnt;i++) { cin>>num[i]; sum+=num[i]; } ave=sum/cnt; for(i=0;i<cnt;i++) { s[i]=ave-num[i]; if(s[i]<0) { s[i]=s[i]*(-1); } cout<<"\n|ave - number| = "<<s[i]; M+=s[i]; } M_D=M/cnt; cout<<"\n\n Average: "<<ave; cout<<"\n MD(Mean Deviation): "<<M_D; getch(); return 0;
}