Calculer la moyenne et l'écart type à partir d'un vecteur d'échantillons en C++ en utilisant Boost

Existe-t-il un moyen de calculer la moyenne et l'écart-type pour un vecteur contenant des échantillons en utilisant Boost?

Ou dois-je créer un accumulateur et y introduire le vecteur?

77
demandé sur Peter Mortensen 2011-10-01 01:59:41

8 réponses

Utilisation d'accumulateurs est la manière de calculer les moyens et les écarts-types dans 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;

 

43
répondu David Nehme 2017-07-31 19:30:14

Je ne sais pas si Boost a des fonctions plus spécifiques, mais vous pouvez le faire avec la bibliothèque standard.

Étant donné std::vector<double> v, c'est la manière naïve:

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

Ceci est susceptible de débordement ou de sous-débit pour des valeurs énormes ou minuscules. Une façon légèrement meilleure de calculer l'écart-type est:

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

Mise à jour pour C++11:

L'appel à std::transform peut être écrit en utilisant une fonction lambda au lieu de std::minus et std::bind2nd (maintenant obsolète):

std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
175
répondu musiphil 2017-03-28 20:30:14

Si la performance est importante pour vous, et que votre compilateur prend en charge lambdas, le calcul stdev peut être rendu plus rapide et plus simple: dans les tests avec VS 2012, j'ai trouvé que le code suivant est plus de 10 X plus rapide que le code Boost donné dans la réponse choisie; il est également 5 X plus rapide

notez que j'utilise un exemple d'écart-type, donc le code ci-dessous donne des résultats légèrement différents (Pourquoi il y a un moins Un en écarts types)

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));
53
répondu Josh Greifer 2015-07-24 09:43:24

Ma réponse est similaire à Josh Greifer mais généralisée à la covariance de l'échantillon. La variance d'échantillon est juste la covariance d'échantillon mais avec les deux entrées identiques. Cela inclut la corrélation de Bessel.

    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);
    }
1
répondu SmallChess 2015-12-14 00:26:45

2 fois plus rapide que les versions mentionnées précédemment-principalement parce que les boucles transform() et inner_product() sont jointes. Désolé pour mon raccourci / typedefs / macro: Flo = float. Cit = itération const. CR const réf. Vflo-vecteur. Testé dans VS2010

Flo     stdDev2(VFlo CR crVec) {
    SZ  n = crVec.size();                               if (n < 2) return 0.0f;
    Flo fSqSum = 0.0f, fSum = 0.0f;
    Cit(VFlo, crVec) {
        Flo f   = *cx;
        fSqSum  += f * f; 
        fSum    += f;
    } 
    Flo fSumSq      = fSum * fSum;
    Flo fSumSqDivN  = fSumSq / n;
    Flo fSubSqSum   = fSqSum - fSumSqDivN;
    Flo preSqrt     = fSubSqSum / (n-1);
    return  sqrt(preSqrt);
}
0
répondu slyy2048 2017-10-25 02:46:28

En améliorant la réponse de musiphil ci-dessus , vous pouvez écrire une fonction d'écart-type sans le vecteur temporaire diff, en utilisant simplement un seul appel inner_product avec les capacités lambda C++11:

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

Je soupçonne que faire la soustraction plusieurs fois est moins cher que d'utiliser un stockage intermédiaire supplémentaire, et je pense qu'il est plus lisible, mais je n'ai pas encore testé la performance.

0
répondu codeling 2018-08-13 13:31:20

Créez votre propre conteneur:

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

Il a quelques limites, mais il fonctionne magnifiquement quand vous savez ce que vous faites.

-2
répondu Sushant Kondguli 2017-01-31 14:03:52

/ / signifie déviation en C++

/Un écart qui est de la différence entre la valeur observée et la valeur vraie d'une grandeur d'intérêt (comme une moyenne de population) est une erreur et un écart est la différence entre la valeur observée et une estimation de la vraie valeur (une telle estimation peut être une moyenne d'échantillon) est un résiduelle. Ces concepts s'appliquent aux données aux niveaux d'intervalle et de rapport de mesure./

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

}

-6
répondu ali 2016-08-07 08:24:15