Có cách nào để tính giá trị trung bình và độ lệch chuẩn cho vectơ chứa mẫu bằng cách sử dụng Boost không?
Hay tôi phải tạo một bộ tích lũy và nạp vectơ vào đó?
Có cách nào để tính giá trị trung bình và độ lệch chuẩn cho vectơ chứa mẫu bằng cách sử dụng Boost không?
Hay tôi phải tạo một bộ tích lũy và nạp vectơ vào đó?
Câu trả lời:
Sử dụng bộ tích lũy là cách để tính toán phương tiện và độ lệch chuẩn trong 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
sẽ tạo ra kết quả không chính xác nếu phương sai rất nhỏ do lỗi làm tròn. Nó thực sự có thể tạo ra phương sai âm.
Tôi không biết liệu Boost có các chức năng cụ thể hơn hay không, nhưng bạn có thể làm điều đó với thư viện tiêu chuẩn.
Giả sử std::vector<double> v
, đây là cách ngây thơ:
#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);
Điều này dễ bị tràn hoặc tràn đối với các giá trị lớn hoặc nhỏ. Một cách tốt hơn một chút để tính độ lệch chuẩn là:
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ẬP NHẬT cho C ++ 11:
Lệnh gọi tới std::transform
có thể được viết bằng hàm lambda thay vì std::minus
và std::bind2nd
(hiện không được dùng nữa):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
tính toán ở phần trên cùng.
(v.size() - 1)
cho v.size()
trong dòng cuối cùng trên: std::sqrt(sq_sum / (v.size() - 1))
. (Đối với phương pháp đầu tiên, đó là một chút phức tạp: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
cho tổng các hình vuông là rất gọn gàng.
Nếu hiệu suất là quan trọng đối với bạn và trình biên dịch của bạn hỗ trợ lambdas, thì việc tính toán stdev có thể được thực hiện nhanh hơn và đơn giản hơn: Trong các thử nghiệm với VS 2012, tôi nhận thấy rằng mã sau nhanh hơn 10 X so với mã Boost được đưa ra trong câu trả lời đã chọn ; nó cũng nhanh hơn 5 X so với phiên bản an toàn hơn của câu trả lời bằng cách sử dụng các thư viện tiêu chuẩn do musiphil cung cấp.
Lưu ý rằng tôi đang sử dụng độ lệch chuẩn mẫu, vì vậy đoạn mã dưới đây cho kết quả hơi khác ( Tại sao lại có điểm trừ một trong độ lệch chuẩn )
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()
chức năng được bổ sung theo tiêu chuẩn 11 C ++ đối với trường hợp khi không có gì giống như là v.end()
. Các std::end
thể bị quá tải cho container ít tiêu chuẩn - xem en.cppreference.com/w/cpp/iterator/end
Cải thiện câu trả lời bằng musiphil , bạn có thể viết một hàm độ lệch chuẩn mà không cần vectơ tạm thời diff
, chỉ cần sử dụng một inner_product
lệnh gọi với các khả năng lambda của 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 ));
}
Tôi nghi ngờ việc thực hiện phép trừ nhiều lần sẽ rẻ hơn so với việc sử dụng thêm bộ nhớ trung gian và tôi nghĩ nó dễ đọc hơn, nhưng tôi chưa kiểm tra hiệu suất.
Có vẻ như giải pháp đệ quy thanh lịch sau đây đã không được đề cập đến, mặc dù nó đã có từ lâu. Đề cập đến Nghệ thuật lập trình máy tính của 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);
thì đối với danh sách các n>=2
giá trị, ước tính của độ lệch chuẩn là:
stddev = std::sqrt(variance_n / (n-1)).
Hi vọng điêu nay co ich!
Câu trả lời của tôi tương tự như Josh Greifer nhưng được tổng quát hóa thành hiệp phương sai mẫu. Phương sai mẫu chỉ là hiệp phương sai mẫu nhưng với hai đầu vào giống hệt nhau. Điều này bao gồm mối tương quan của 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);
}
Nhanh hơn gấp 2 lần so với các phiên bản được đề cập trước đây - chủ yếu là do các vòng lặp biến đổi () và nội_sản_phẩm () được kết hợp với nhau. Xin lỗi về phím tắt / typedefs / macro: Flo = float của tôi. CR const ref. VFlo - vectơ. Đã thử nghiệm trong 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; }
không?
Tạo vùng chứa của riêng bạn:
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();
}
};
Nó có một số hạn chế, nhưng nó hoạt động tốt khi bạn biết mình đang làm gì.
// có nghĩa là độ lệch trong c ++
/ Độ lệch là sự khác biệt giữa giá trị quan sát và giá trị thực của một đại lượng quan tâm (chẳng hạn như giá trị trung bình tổng thể) là một sai số và độ lệch là sự khác biệt giữa giá trị quan sát được và ước tính của giá trị thực (chẳng hạn một ước tính có thể là trung bình mẫu) là phần dư. Các khái niệm này có thể áp dụng cho dữ liệu ở các mức đo khoảng cách và tỷ lệ. /
#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;
}