Apakah ada cara untuk menghitung mean dan deviasi standar untuk vektor yang mengandung sampel menggunakan Boost ?
Atau apakah saya harus membuat akumulator dan memasukkan vektor ke dalamnya?
Apakah ada cara untuk menghitung mean dan deviasi standar untuk vektor yang mengandung sampel menggunakan Boost ?
Atau apakah saya harus membuat akumulator dan memasukkan vektor ke dalamnya?
Jawaban:
Menggunakan akumulator adalah cara untuk menghitung rata-rata dan deviasi standar di 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
yang akan menghasilkan hasil yang salah jika varians sangat kecil karena kesalahan pembulatan. Ini sebenarnya dapat menghasilkan varian negatif.
Saya tidak tahu apakah Boost memiliki fungsi yang lebih spesifik, tetapi Anda dapat melakukannya dengan pustaka standar.
Diberikan std::vector<double> v
, ini adalah cara yang naif:
#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);
Ini rentan terhadap overflow atau underflow untuk nilai besar atau kecil. Cara yang sedikit lebih baik untuk menghitung deviasi standar adalah:
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());
UPDATE untuk C ++ 11:
Panggilan ke std::transform
dapat ditulis menggunakan fungsi lambda sebagai ganti std::minus
dan std::bind2nd
(sekarang tidak digunakan lagi):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
hitung di bagian atas.
(v.size() - 1)
untuk v.size()
di baris terakhir di atas: std::sqrt(sq_sum / (v.size() - 1))
. (Untuk metode pertama, itu sedikit rumit: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
untuk jumlah kotak sangat rapi.
Jika kinerja penting bagi Anda, dan kompilator Anda mendukung lambda, penghitungan stdev dapat dibuat lebih cepat dan sederhana: Dalam pengujian dengan VS 2012, saya telah menemukan bahwa kode berikut lebih dari 10 X lebih cepat daripada kode Peningkatan yang diberikan dalam jawaban yang dipilih ; Ini juga 5 X lebih cepat daripada versi jawaban yang lebih aman menggunakan pustaka standar yang diberikan oleh musiphil.
Catatan Saya menggunakan sampel deviasi standar, jadi kode di bawah ini memberikan hasil yang sedikit berbeda ( Mengapa ada Minus Satu dalam Standar Deviasi )
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()
Fungsi ditambahkan oleh C ++ 11 standar untuk kasus-kasus ketika tidak ada yang seperti v.end()
. The std::end
dapat kelebihan beban untuk kontainer kurang standar - lihat en.cppreference.com/w/cpp/iterator/end
Memperbaiki jawaban musiphil , Anda dapat menulis fungsi deviasi standar tanpa vektor sementara diff
, hanya menggunakan satu inner_product
panggilan dengan kapabilitas 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 ));
}
Saya menduga melakukan pengurangan beberapa kali lebih murah daripada menggunakan penyimpanan perantara tambahan, dan menurut saya ini lebih mudah dibaca, tetapi saya belum menguji kinerjanya.
Sepertinya solusi rekursif elegan berikut ini belum pernah disebutkan, meski sudah ada sejak lama. Mengacu pada Seni Pemrograman Komputer 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);
kemudian untuk daftar n>=2
nilai, perkiraan standar deviasi adalah:
stddev = std::sqrt(variance_n / (n-1)).
Semoga ini membantu!
Jawaban saya mirip dengan Josh Greifer tetapi digeneralisasikan ke kovarian sampel. Varians sampel hanyalah kovarians sampel tetapi dengan dua input identik. Ini termasuk korelasi 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 lebih cepat dari versi yang disebutkan sebelumnya - kebanyakan karena loop transform () dan inner_product () digabungkan. Maaf tentang pintasan / typedefs / makro saya: Flo = float. CR const ref. VFlo - vektor. Diuji di 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; }
?
Buat wadah Anda sendiri:
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();
}
};
Itu memang memiliki beberapa batasan, tetapi bekerja dengan baik ketika Anda tahu apa yang Anda lakukan.
// Berarti deviasi dalam c ++
/ Penyimpangan yang merupakan perbedaan antara nilai yang diamati dan nilai sebenarnya dari sejumlah kepentingan (seperti rata-rata populasi) adalah kesalahan dan penyimpangan yang merupakan perbedaan antara nilai yang diamati dan perkiraan nilai sebenarnya (seperti perkiraan mungkin mean sampel) adalah sisa. Konsep-konsep ini berlaku untuk data pada tingkat interval dan rasio pengukuran. /
#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;
}