簡體   English   中英

使用 Boost 計算 C++ 中樣本向量的均值和標准差

[英]Calculate mean and standard deviation from a vector of samples in C++ using Boost

有沒有辦法使用Boost計算包含樣本的向量的均值和標准差?

或者我是否必須創建一個累加器並將向量輸入其中?

不知道Boost有沒有更具體的功能,但是你可以用標准庫來做。

鑒於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更新

可以使用 lambda 函數代替std::minusstd::bind2nd (現已棄用)編寫對std::transform的調用:

std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });

如果性能對您很重要,並且您的編譯器支持 lambda,則可以更快更簡單地進行 stdev 計算:在 VS 2012 測試中,我發現以下代碼比所選答案中給出的 Boost 代碼快 10 倍以上; 它也比使用 musiphil 提供的標准庫的更安全版本的答案快 5 倍。

注意我使用的是樣本標准偏差,所以下面的代碼給出的結果略有不同(為什么標准偏差中有一個減號

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

使用累加器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;

改進musiphil 的答案,您可以編寫沒有臨時向量diff的標准偏差函數,只需使用具有 C++11 lambda 功能的單個inner_product調用:

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 std::sqrt(sq_sum / func.size());
}

我懷疑多次減法比使用額外的中間存儲更便宜,我認為它更具可讀性,但我還沒有測試過性能。

似乎沒有提到以下優雅的遞歸解決方案,盡管它已經存在很長時間了。 參考 Knuth 的計算機編程藝術,

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

那么對於n>=2值的列表,標准偏差的估計是:

stddev = std::sqrt(variance_n / (n-1)). 

希望這可以幫助!

我的答案與 Josh Greifer 相似,但推廣到樣本協方差。 樣本方差只是樣本協方差,但兩個輸入相同。 這包括貝塞爾相關性。

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

比之前提到的版本快 2 倍 - 主要是因為 transform() 和 inner_product() 循環被加入。 抱歉我的快捷方式/typedefs/宏:Flo = float。 CR 常量參考。 VFlo - 向量。 在 VS2010 中測試

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

為了以更好的精度計算樣本均值,可以使用以下 r 步遞歸:

mean_k=1/k*[(kr)*mean_(kr) + sum_over_i_from_(n-r+1)_to_n(x_i)],

其中選擇 r 以使求和分量彼此更接近。

創建自己的容器:

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++中的偏差

/偏差是觀測值與感興趣量的真實值(例如總體平均值)之間的差異是誤差,而偏差是觀察值與真實值估計值之間的差異(例如估計值可能是樣本均值)是殘差。 這些概念適用於測量區間和比率級別的數據。 /

#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 M.D(Mean Deviation): "<<M_D;
getch();
return 0;

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM