![](/img/trans.png)
[英]C++ Data file with an unwanted character: How to remove rogue character and calculate mean, standard deviation and standard error
[英]Calculate mean and standard deviation from a vector of samples in C++ using 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::minus
和std::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.