Calculate mean and standard deviation from a vector of samples in C++ using Boost
有没有办法用boost计算包含样本的向量的平均值和标准偏差?
或者我必须创建一个累加器并将向量输入它?
我不知道Boost是否有更具体的功能,但您可以使用标准库来实现。
考虑到
1 2 3 4 5 6 7 | #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); |
对于较大或较小的值,这很容易发生溢出或下溢。计算标准偏差的更好方法是:
1 2 3 4 5 6 7 8 | 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的更新:
可以使用lambda函数而不是
1 | std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; }); |
如果性能对您很重要,并且您的编译器支持lambda,那么stdev计算可以更快更简单:在使用vs 2012的测试中,我发现以下代码比所选答案中给出的boost代码快10倍以上;它也比使用musi给出的标准库的更安全版本快5倍。菲尔。
注意,我使用的是样本标准差,所以下面的代码给出的结果略有不同(为什么标准差中有一个负的结果)。
1 2 3 4 5 6 7 8 9 | 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)); |
使用累加器是计算增压中平均值和标准偏差的方法。
1 2 3 4 5 | 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; |
。
nbsp;
通过MusiPHIL改进答案,您可以编写一个没有临时矢量EDCOX1〔4〕的标准偏差函数,只需使用一个EDCOX1调用5调用C++ 11 LAMBDA功能:
1 2 3 4 5 6 7 8 | double stddev(std::vector<double> const & func) { double mean = std::accumulate(func.begin(), func.end(), 0.0) / func.size(); double sq_sum = std::inner_product(func.begin(), func.end(), func.begin(), 0.0, [](double const & x, double const & y) { return x + y; }, [mean](double const & x, double const & y) { return (x - mean)*(y - mean); }); return sq_sum / ( func.size() - 1 ); } |
我怀疑多次减法比消耗额外的中间存储要便宜,我认为它更可读,但我还没有测试性能。
比前面提到的版本快2倍-主要是因为transform()和inner_product()循环被连接在一起。抱歉,我的快捷方式/typedefs/macro:flo=float。cr const ref.vflo-矢量。在VS2010中测试
1 2 3 4 5 6 7 8 9 10 11 12 | #define fe(EL, CONTAINER) for each (auto EL in CONTAINER) //VS2010 Flo stdDev(VFlo CR crVec) { SZ n = crVec.size(); if (n < 2) return 0.0f; Flo fSqSum = 0.0f, fSum = 0.0f; fe(f, crVec) fSqSum += f * f; // EDIT: was Cit(VFlo, crVec) { fe(f, crVec) fSum += f; Flo fSumSq = fSum * fSum; Flo fSumSqDivN = fSumSq / n; Flo fSubSqSum = fSqSum - fSumSqDivN; Flo fPreSqrt = fSubSqSum / (n - 1); return sqrt(fPreSqrt); } |
。
我的答案与乔希·格里弗相似,但被概括为样本协方差。样本方差只是样本协方差,但两个输入相同。这包括贝塞尔的相关性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); } |
。
下面这个优雅的递归解决方案似乎没有被提到,尽管它已经存在很长时间了。参考Knuth的计算机编程艺术,
1 2 3 4 5 | mean_1 = x_1, variance_1 = 0; //initial conditions; edge case; //for k >= 2, mean_k = mean_k-1 + (x_k - mean_k-1) / k; variance_k = variance_k-1 + (x_k - mean_k-1) * (x_k - mean_k); |
。
然后,对于
1 | std = variance_n / (n-1). |
号
希望这有帮助!
创建自己的容器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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(); } }; |
它确实有一些局限性,但是当你知道你在做什么的时候,它会很好地工作。
C++中的偏差
/一个偏差是一个观察值和一个感兴趣量的真实值(如总体平均值)之间的差,是一个误差,而一个偏差是观察值和真实值的估计值之间的差(这种估计值可能是一个样本平均值)是一个余数。这些概念适用于测量间隔和比率级别的数据。/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #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<<" |ave - number| ="<<s[i]; M+=s[i]; } M_D=M/cnt; cout<<" Average: "<<ave; cout<<" M.D(Mean Deviation):"<<M_D; getch(); return 0; |
。
}