¿Hay alguna manera de calcular la desviación estándar y media de un vector que contiene muestras usando Boost ?
¿O tengo que crear un acumulador e introducir el vector en él?
¿Hay alguna manera de calcular la desviación estándar y media de un vector que contiene muestras usando Boost ?
¿O tengo que crear un acumulador e introducir el vector en él?
Respuestas:
El uso de acumuladores es la forma de calcular las medias y las desviaciones estándar en 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
que producirá un resultado incorrecto si la varianza es muy pequeña debido a errores de redondeo. De hecho, puede producir una variación negativa.
No sé si Boost tiene funciones más específicas, pero puedes hacerlo con la biblioteca estándar.
Dado std::vector<double> v
, esta es la forma ingenua:
#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);
Esto es susceptible de desbordamiento o subdesbordamiento para valores grandes o pequeños. Una forma ligeramente mejor de calcular la desviación estándar es:
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());
ACTUALIZACIÓN para C ++ 11:
La llamada a std::transform
se puede escribir usando una función lambda en lugar de std::minus
y std::bind2nd
(ahora en desuso):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
calculado en la parte superior.
(v.size() - 1)
por v.size()
la última línea anterior: std::sqrt(sq_sum / (v.size() - 1))
. (Para el primer método, que es un poco complicado: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
para suma de cuadrados es muy bueno.
Si el rendimiento es importante para usted y su compilador admite lambdas, el cálculo de stdev se puede hacer más rápido y más simple: en las pruebas con VS 2012, descubrí que el siguiente código es más de 10 veces más rápido que el código Boost dado en la respuesta elegida ; también es 5 veces más rápido que la versión más segura de la respuesta usando bibliotecas estándar proporcionadas por musiphil.
Tenga en cuenta que estoy usando una desviación estándar de muestra, por lo que el siguiente código da resultados ligeramente diferentes (por qué hay un menos uno en las desviaciones estándar )
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()
función fue agregada por el estándar C ++ 11 para casos en los que no hay nada parecido v.end()
. Se std::end
puede sobrecargar para el contenedor menos estándar; consulte en.cppreference.com/w/cpp/iterator/end
Mejorando la respuesta de musiphil , puede escribir una función de desviación estándar sin el vector temporal diff
, simplemente usando una sola inner_product
llamada con las capacidades lambda de 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 ));
}
Sospecho que hacer la resta varias veces es más barato que usar almacenamiento intermedio adicional, y creo que es más legible, pero aún no he probado el rendimiento.
Parece que la siguiente solución recursiva elegante no se ha mencionado, aunque ha existido durante mucho tiempo. Refiriéndose al arte de la programación informática de Knuth,
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);
luego, para una lista de n>=2
valores, la estimación de la desviación estándar es:
stddev = std::sqrt(variance_n / (n-1)).
¡Espero que esto ayude!
Mi respuesta es similar a la de Josh Greifer pero generalizada a la covarianza de muestra. La varianza de la muestra es solo la covarianza de la muestra, pero con las dos entradas idénticas. Esto incluye la correlación 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);
}
2 veces más rápido que las versiones mencionadas anteriormente, principalmente porque los bucles transform () e inner_product () están unidos. Lo siento por mi atajo / typedefs / macro: Flo = float. CR const ref. VFlo - vector. Probado en 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; }
?
Crea tu propio contenedor:
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();
}
};
Tiene algunas limitaciones, pero funciona de maravilla cuando sabes lo que estás haciendo.
// significa desviación en c ++
/ Una desviación que es una diferencia entre un valor observado y el valor real de una cantidad de interés (como la media de una población) es un error y una desviación que es la diferencia entre el valor observado y una estimación del valor real (como una estimación puede ser una media muestral) es un residuo. Estos conceptos son aplicables a los datos en los niveles de medición de intervalo y razón. /
#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;
}