Gibt es eine Möglichkeit, den Mittelwert und die Standardabweichung für einen Vektor, der Stichproben enthält, mit Boost zu berechnen?
Oder muss ich einen Akkumulator erstellen und den Vektor einspeisen?
Die Verwendung von Akkumulatoren ist die Methode, 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;
Ich weiß nicht, ob Boost spezifischere Funktionen hat, aber Sie können dies mit der Standardbibliothek tun.
Bei std::vector<double> v
Ist dies 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 ist anfällig für Über- oder Unterlauf bei großen oder kleinen Werten. 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; });
Wenn Leistung für Sie 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 über 10-mal schneller ist als der in der ausgewählten Antwort angegebene Boost-Code ; Es ist außerdem 5-mal schneller als die sicherere Version der Antwort, wenn Standardbibliotheken von musiphil verwendet werden.
Hinweis: Ich verwende eine Standardabweichung für die Stichprobe, daher liefert der folgende Code leicht abweichende Ergebnisse ( Warum gibt es eine Minus Eins in Standardabweichungen )
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));
Indem Sie die Antwort von musiphil verbessern, können Sie eine Standardabweichungsfunktion ohne den temporären Vektor diff
schreiben, indem Sie nur einen einzelnen inner_product
Aufruf mit den C++ 11 Lambda-Fähigkeiten:
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 dies besser lesbar ist, aber ich habe die Leistung noch nicht getestet.
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);
}
Meine Antwort ist ähnlich wie Josh Greifer, aber verallgemeinert auf die Kovarianz. Die Stichprobenvarianz ist nur eine Stichproben-Kovarianz, wobei jedoch die beiden Eingänge identisch sind. Dies schließt die Besselsche 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);
}
Es scheint, dass die folgende elegante rekursive Lösung nicht erwähnt wurde, obwohl es sie schon lange gibt. Unter Bezugnahme 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);
dann für eine Liste von n>=2
Werte, die Schätzung der Standardabweichung ist:
std = variance_n / (n-1).
Hoffe das hilft!