มีวิธีคำนวณค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานสำหรับเวกเตอร์ที่มีตัวอย่างโดยใช้Boostหรือไม่?
หรือฉันต้องสร้างตัวสะสมและป้อนเวกเตอร์เข้าไป
มีวิธีคำนวณค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานสำหรับเวกเตอร์ที่มีตัวอย่างโดยใช้Boostหรือไม่?
หรือฉันต้องสร้างตัวสะสมและป้อนเวกเตอร์เข้าไป
คำตอบ:
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
ผลรวมของกำลังสองเป็นไปอย่างเรียบร้อย
หากประสิทธิภาพเป็นสิ่งสำคัญสำหรับคุณและคอมไพเลอร์ของคุณรองรับ lambdas การคำนวณ stdev สามารถทำได้เร็วขึ้นและง่ายขึ้น: ในการทดสอบด้วย VS 2012 ฉันพบว่าโค้ดต่อไปนี้เร็วกว่าโค้ด Boost ที่ระบุไว้ในคำตอบที่เลือกมากกว่า 10 X ; นอกจากนี้ยังเร็วกว่าคำตอบเวอร์ชันที่ปลอดภัยกว่าถึง 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 lambda:
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());
}
ฉันสงสัยว่าการลบหลาย ๆ ครั้งนั้นถูกกว่าการใช้พื้นที่จัดเก็บข้อมูลเพิ่มเติมระดับกลางและฉันคิดว่ามันอ่านได้มากกว่า แต่ฉันยังไม่ได้ทดสอบประสิทธิภาพ
ดูเหมือนว่าจะไม่มีการกล่าวถึงโซลูชันการเรียกซ้ำที่สวยงามดังต่อไปนี้แม้ว่าจะมีมานานแล้วก็ตาม อ้างถึงศิลปะการเขียนโปรแกรมคอมพิวเตอร์ของ 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);
จากนั้นสำหรับรายการn>=2
ค่าค่าประมาณของส่วนเบี่ยงเบนมาตรฐานคือ:
stddev = std::sqrt(variance_n / (n-1)).
หวังว่านี่จะช่วยได้!
คำตอบของฉันคล้ายกับ Josh Greifer แต่เป็นข้อมูลทั่วไปของความแปรปรวนร่วมของตัวอย่าง ความแปรปรวนตัวอย่างเป็นเพียงความแปรปรวนร่วมตัวอย่าง แต่มีอินพุตทั้งสองเหมือนกัน ซึ่งรวมถึงความสัมพันธ์ของ 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 เท่า - ส่วนใหญ่เป็นเพราะลูป transform () และ inner_product () เข้าด้วยกัน ขออภัยเกี่ยวกับทางลัด / typedefs / มาโครของฉัน: Flo = float CR const อ้างอิง 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;
}