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?
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?
Réponses:
L'utilisation d'accumulateurs est le moyen de calculer les moyennes 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;
second moment - squared mean
qui produira un résultat incorrect si la variance est très petite en raison d'erreurs d'arrondi. Cela peut en fait produire une variance négative.
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épassement pour des valeurs énormes ou minuscules. Une meilleure façon 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 à l'aide d'une fonction lambda au lieu de std::minus
and std::bind2nd
(désormais obsolète):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
calculée dans la partie supérieure.
(v.size() - 1)
à v.size()
la dernière ligne ci - dessus: std::sqrt(sq_sum / (v.size() - 1))
. (Pour la première méthode, il est un peu compliqué: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
de la somme des carrés est très soignée.
Si les performances sont importantes pour vous et que votre compilateur prend en charge les lambdas, le calcul stdev peut être plus rapide et plus simple: dans les tests avec VS 2012, j'ai trouvé que le code suivant est plus de 10 fois plus rapide que le code Boost donné dans la réponse choisie ; c'est aussi 5 fois plus rapide que la version la plus sûre de la réponse utilisant les bibliothèques standard fournies par musiphil.
Remarque 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 dans les é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));
std::end()
fonction a été ajoutée par la norme C ++ 11 pour les cas où il n'y a rien de tel v.end()
. Le std::end
peut être surchargé pour le conteneur moins standard - voir en.cppreference.com/w/cpp/iterator/end
En améliorant la réponse par musiphil , vous pouvez écrire une fonction d'écart type sans le vecteur temporaire diff
, en utilisant simplement un seul inner_product
appel 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 std::sqrt(sq_sum / ( func.size() - 1 ));
}
Je soupçonne que faire la soustraction plusieurs fois est moins cher que d'utiliser du stockage intermédiaire supplémentaire, et je pense que c'est plus lisible, mais je n'ai pas encore testé les performances.
Il semble que l'élégante solution récursive suivante n'ait pas été mentionnée, bien qu'elle existe depuis longtemps. Se référant à l'art de Knuth de la programmation informatique,
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);
alors pour une liste de n>=2
valeurs, l'estimation de l'écart type est:
stddev = std::sqrt(variance_n / (n-1)).
J'espère que cela t'aides!
Ma réponse est similaire à celle de Josh Greifer mais généralisée à la covariance de l'échantillon. La variance de l'échantillon n'est que la covariance de l'é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);
}
2x plus rapide que les versions précédentes - principalement parce que les boucles transform () et inner_product () sont jointes. Désolé pour mon raccourci / typedefs / macro: Flo = float. CR const réf. VFlo - vecteur. Testé dans 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; }
?
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 certaines limites, mais cela fonctionne à merveille lorsque vous savez ce que vous faites.
// signifie une déviation en c ++
/ Un écart qui est une différence entre une valeur observée et la valeur réelle d'une quantité d'intérêt (telle qu'une moyenne de population) est une erreur et un écart qui est la différence entre la valeur observée et une estimation de la valeur réelle (telle une estimation peut être une moyenne d'échantillon) est un résidu. 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;
}