Вычислите среднее и стандартное отклонение от вектора выборок в C++ с помощью Boost
есть ли способ вычислить среднее и стандартное отклонение для вектора, содержащего образцы, используя Boost?
или мне нужно создать аккумулятор и подать в него вектор?
8 ответов:
использование аккумуляторов и способ вычисления средних и стандартных отклонений в 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;
Я не знаю, есть ли у Boost более конкретные функции, но вы можете сделать это со стандартной библиотекой.
дано
std::vector<double> v
, это наивно так:#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);
это восприимчиво к переполнению или underflow для огромных или крошечных значений. Немного лучший способ рассчитать стандартное отклонение:
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());
обновление для C++11:
вызов
std::transform
можно записать с помощью лямбда-функции вместоstd::minus
иstd::bind2nd
(сейчас устарел):std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
если производительность важна для вас, и ваш компилятор поддерживает lambdas, вычисление stdev может быть сделано быстрее и проще: в тестах с VS 2012 я обнаружил, что следующий код более чем на 10 X быстрее, чем код Boost, указанный в выбранном ответе; это также на 5 X быстрее, чем более безопасная версия ответа с использованием стандартных библиотек, предоставленных musiphil.
Примечание я использую образец стандартного отклонения, поэтому приведенный ниже код дает несколько иные результаты (почему есть минус один в стандартных отклонениях)
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));
мой ответ похож на Джоша грейфера, но обобщен для выборки ковариации. Выборочная дисперсия-это просто выборочная ковариация, но с двумя идентичными входами. Это включает в себя корреляцию Бесселя.
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 быстрее, чем упомянутые выше версии - в основном потому, что циклы transform() и inner_product() объединены. Извините за мой ярлык / typedefs / macro: Flo = float. Cit = const итерация. КЛ константная ссылка. Вфло-вектор. Испытания в 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); }
улучшение ответ от musiphil выше, вы можете написать функцию стандартного отклонения без временного вектора
diff
, просто используя одинinner_product
вызов с возможностями лямбда 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 ); }
Я подозреваю, что вычитание в несколько раз дешевле, чем использование дополнительного промежуточного хранилища, и я думаю, что это более читаемо, но я еще не тестировал производительность.
создайте свой собственный контейнер:
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(); } };
у него есть некоторые ограничения, но он прекрасно работает, когда вы знаете, что делаете.
/ / означает отклонение в c++
/отклонение, которое является разницей между наблюдаемым значением и истинным значением интересующей величины (например, среднее значение популяции), является ошибкой, а отклонение, которое является разницей между наблюдаемым значением и оценкой истинного значения (такая оценка может быть выборочным средним), является остаточным. Эти понятия применимы к данным на интервальных и относительных уровнях измерения./
#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;
}