Чи є спосіб обчислити середнє та стандартне відхилення для вектора, що містить зразки, за допомогою Boost ?
Або мені потрібно створити акумулятор і подати в нього вектор?
Чи є спосіб обчислити середнє та стандартне відхилення для вектора, що містить зразки, за допомогою Boost ?
Або мені потрібно створити акумулятор і подати в нього вектор?
Відповіді:
Використання акумуляторів - це спосіб обчислення середніх значень та стандартних відхилень у 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
це дасть неправильний результат, якщо дисперсія дуже мала через помилки округлення. Це насправді може спричинити негативну дисперсію.
Не знаю, чи 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);
Це сприйнятливо до переповнення або затоплення для величезних або крихітних значень. Трохи кращим способом обчислення стандартного відхилення є:
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; });
mean
обчисленого у верхній частині.
(v.size() - 1)
на v.size()
в останньому рядку вище: std::sqrt(sq_sum / (v.size() - 1))
. (Для першого методу це трохи складно: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
...
std::inner_product
для суми квадратів дуже акуратне.
Якщо для вас важлива продуктивність, і ваш компілятор підтримує лямбди, обчислення stdev можна зробити швидше і простіше: У тестах з VS 2012 я виявив, що наступний код на 10 разів швидший, ніж код Boost, вказаний у вибраній відповіді ; це також в 5 разів швидше, ніж безпечніша версія відповіді, використовуючи стандартні бібліотеки, надані 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));
std::end()
Функція була додана в відповідності зі стандартом C ++ 11 для випадків , коли немає нічого подібного v.end()
. std::end
Може бути перевантажений для менш стандартного контейнера - см en.cppreference.com/w/cpp/iterator/end
Поліпшення на відповідь по 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 std::sqrt(sq_sum / ( func.size() - 1 ));
}
Я підозрюю, що робити віднімання кілька разів дешевше, ніж використовувати додаткове проміжне сховище, і я думаю, що це читабельніше, але я ще не перевірив продуктивність.
Здається, наступне елегантне рекурсивне рішення не згадувалося, хоча воно існує довгий час. Посилаючись на мистецтво комп’ютерного програмування Кнута,
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);
тоді для списку n>=2
значень оцінка стандартного відхилення становить:
stddev = std::sqrt(variance_n / (n-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);
}
Удвічі швидше, ніж у згаданих версіях - здебільшого тому, що цикли transform () та inner_product () об’єднані. Вибачте про мій ярлик / typedefs / macro: Flo = float. CR const ref. VFlo - вектор. Перевірено у 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; }
?
Створіть власний контейнер:
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;
}