Gibt es eine Möglichkeit, den Mittelwert und die Standardabweichung für einen Vektor mit Proben mithilfe von Boost zu berechnen ?
Oder muss ich einen Akkumulator erstellen und den Vektor einspeisen?
Gibt es eine Möglichkeit, den Mittelwert und die Standardabweichung für einen Vektor mit Proben mithilfe von Boost zu berechnen ?
Oder muss ich einen Akkumulator erstellen und den Vektor einspeisen?
Antworten:
Die Verwendung von Akkumulatoren ist der Weg, um Mittelwerte und Standardabweichungen in Boost zu berechnen .
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
Dies führt zu einem falschen Ergebnis, wenn die Varianz aufgrund von Rundungsfehlern sehr gering ist. Es kann tatsächlich eine negative Varianz erzeugen.
Ich weiß nicht, ob Boost spezifischere Funktionen hat, aber Sie können dies mit der Standardbibliothek tun.
Vorausgesetzt std::vector<double> v
, dies ist der naive Weg:
#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);
Dies kann bei großen oder kleinen Werten zu Über- oder Unterlauf führen. Eine etwas bessere Methode zur Berechnung der Standardabweichung ist:
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());
UPDATE für C ++ 11:
Der Aufruf von std::transform
kann mit einer Lambda-Funktion anstelle von std::minus
und std::bind2nd
(jetzt veraltet) geschrieben werden:
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
im oberen Teil berechnet wurde.
(v.size() - 1)
für v.size()
oben in der letzten Zeile: std::sqrt(sq_sum / (v.size() - 1))
. (Für die erste Methode, es ist ein wenig kompliziert: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
für die Summe der Quadrate ist sehr ordentlich.
Wenn Ihnen die Leistung wichtig ist und Ihr Compiler Lambdas unterstützt, kann die stdev-Berechnung schneller und einfacher durchgeführt werden: In Tests mit VS 2012 habe ich festgestellt, dass der folgende Code mehr als 10-mal schneller ist als der in der ausgewählten Antwort angegebene Boost-Code ;; Es ist auch 5-mal schneller als die sicherere Version der Antwort mit Standardbibliotheken von musiphil.
Hinweis: Ich verwende die Standardabweichung des Beispiels, daher liefert der folgende Code leicht unterschiedliche Ergebnisse ( Warum es in Standardabweichungen ein Minus eins gibt )
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()
Funktion wurde vom C ++ 11-Standard für Fälle hinzugefügt, in denen es nichts Vergleichbares gibt v.end()
. Die std::end
können für den weniger Standardcontainer überladen werden - siehe en.cppreference.com/w/cpp/iterator/end
Die Verbesserung des auf der Antwort von musiphil , können Sie eine Standardabweichung Funktion ohne den temporären Vektor schreiben diff
, nur ein einziges mit inner_product
Gespräch mit dem C ++ 11 Lambda - Funktionen:
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 ));
}
Ich vermute, dass die mehrfache Subtraktion billiger ist als die Verwendung von zusätzlichem Zwischenspeicher, und ich denke, dass sie besser lesbar ist, aber ich habe die Leistung noch nicht getestet.
Es scheint, dass die folgende elegante rekursive Lösung nicht erwähnt wurde, obwohl es sie schon lange gibt. In Bezug auf Knuths Kunst der Computerprogrammierung,
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);
Für eine Liste von n>=2
Werten lautet die Schätzung der Standardabweichung:
stddev = std::sqrt(variance_n / (n-1)).
Hoffe das hilft!
Meine Antwort ist ähnlich wie die von Josh Greifer, aber verallgemeinert, um die Kovarianz zu untersuchen. Die Stichprobenvarianz ist nur die Stichproben-Kovarianz, wobei die beiden Eingänge identisch sind. Dies schließt Bessels Korrelation ein.
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);
}
2x schneller als die zuvor genannten Versionen - hauptsächlich, weil transform () - und inner_product () -Schleifen verbunden sind. Entschuldigung für meine Verknüpfung / typedefs / macro: Flo = float. CR const ref. VFlo - Vektor. Getestet in 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; }
?
Erstellen Sie Ihren eigenen Container:
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();
}
};
Es hat einige Einschränkungen, aber es funktioniert wunderbar, wenn Sie wissen, was Sie tun.
// bedeutet Abweichung in c ++
/ Eine Abweichung, die eine Differenz zwischen einem beobachteten Wert und dem wahren Wert einer interessierenden Größe (z. B. einem Populationsmittelwert) ist, ist ein Fehler und eine Abweichung, die die Differenz zwischen dem beobachteten Wert und einer Schätzung des wahren Werts (z Eine Schätzung kann ein Stichprobenmittelwert sein. Diese Konzepte gelten für Daten in den Intervall- und Verhältnisniveaus der Messung. /.
#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;
}}