を使用してサンプルを含むベクトルの平均と標準偏差を計算する方法はありますか Boostますか?
または、アキュムレータを作成してベクターをそこにフィードする必要がありますか?
を使用してサンプルを含むベクトルの平均と標準偏差を計算する方法はありますか 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;
second moment - squared mean
は、丸め誤差のために分散が非常に小さい場合、誤った結果を生成します。実際に負の分散を生成する可能性があります。
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の更新:
への呼び出しstd::transform
はstd::minus
、std::bind2nd
以下の代わりにラムダ関数を使用して記述できます(現在は非推奨):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
は上部で計算された値に依存します。
(v.size() - 1)
ためv.size()
、上記の最後の行に:std::sqrt(sq_sum / (v.size() - 1))
。(第一の方法の場合、それは少し複雑です:std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
。
std::inner_product
二乗和に使用するのは非常に便利です。
パフォーマンスが重要であり、コンパイラがラムダをサポートしている場合は、stdev計算をより速く簡単にすることができます。VS2012でのテストでは、次のコードは、選択した回答で指定されたBoostコードよりも10倍以上速いことがわかりました; また、musiphilが提供する標準ライブラリを使用した安全なバージョンの回答よりも5倍高速です。
注:標準偏差のサンプルを使用しているため、以下のコードでは若干異なる結果が得られます(標準偏差にマイナス1がある理由)
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));
std::end()
関数は、C ++ 11標準によって、のようなものがない場合に追加されましたv.end()
。std::end
参照-レス標準コンテナのために、オーバーロードすることができますen.cppreference.com/w/cpp/iterator/end
musiphilによる答えを改善して、C ++ 11ラムダ機能でdiff
単一の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() - 1 ));
}
減算を複数回実行する方が、追加の中間ストレージを使用するよりも安価であると思います。読みやすいと思いますが、まだパフォーマンスをテストしていません。
次のエレガントな再帰ソリューションは、長い間使用されてきましたが、言及されていないようです。KnuthのArt of Computer Programmingを参照すると、
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)).
お役に立てれば!
私の答えはジョシュグライファーと似ていますが、共分散のサンプルに一般化されています。サンプル分散はサンプルの共分散ですが、2つの入力は同じです。これにはベッセルの相関が含まれます。
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 const ref。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);
}
for( float f : crVec ) { fSqSum += f * f; fSum += f; }
か?
独自のコンテナを作成します。
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;
}