বুস্ট ব্যবহার করে সি ++ তে নমুনার ভেক্টর থেকে গড় এবং স্ট্যান্ডার্ড বিচ্যুতি গণনা করুন


91

বুস্ট ব্যবহার করে নমুনা সম্বলিত ভেক্টরের জন্য গড় এবং স্ট্যান্ডার্ড বিচ্যুতি গণনার কোনও উপায় আছে কি ?

বা আমাকে কী একটি সঞ্চয়ী তৈরি করতে এবং এতে ভেক্টরকে খাওয়ানো উচিত?


এক পাসের সমাধানের জন্য দেখুন স্ট্যাকওভারফ্লো.com
গুলজার

উত্তর:


52

Accumulators ব্যবহার হয় উপায় উপায়ে এবং স্ট্যান্ডার্ড ডেভিয়েশন গনা বুস্ট

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;

 


4
দ্রষ্টব্য, এই ট্যাগ :: বৈকল্পিক আনুমানিক সূত্র দ্বারা বৈকল্পিক গণনা করে। ট্যাগ :: ভেরিয়েন্স (অলস) একটি নির্দিষ্ট সূত্র ধরে গণনা করে, বিশেষভাবে: second moment - squared meanযা গোলটি ত্রুটির কারণে ভেরিয়েন্স খুব ছোট হলে ভুল ফলাফল আনবে। এটি আসলে নেতিবাচক বৈকল্পিক উত্পাদন করতে পারে।
পান্ডা -34

পুনরাবৃত্ত (অনলাইন) অ্যালগরিদম ব্যবহার করুন যদি আপনি জানেন যে আপনার কাছে প্রচুর সংখ্যা রয়েছে। এটি নীচে এবং ওভারফ্লো উভয় সমস্যার যত্ন নেবে।
কেমিন

219

আমি জানি না বুস্টের আরও নির্দিষ্ট ফাংশন রয়েছে কিনা তবে আপনি এটি স্ট্যান্ডার্ড লাইব্রেরি দিয়ে করতে পারেন।

প্রদত্ত 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());

সি ++ 11 এর জন্য আপডেট করুন :

কলটির std::transformপরিবর্তে ল্যাম্বডা ফাংশন ব্যবহার করে std::minusএবং std::bind2nd(এখন অবহেলিত) লেখা যেতে পারে :

std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });

4
হ্যাঁ; স্পষ্টতই, নীচের অংশটি meanউপরের অংশে গণনার মানের উপর নির্ভর করে ।
মুসিফিল

7
সমীকরণের প্রথম সেটটি কাজ করে না। আমি ইন্টি 10 ​​এবং 2 রেখেছি এবং 4 এর আউটপুট পেয়েছি a এক নজরে আমি মনে করি এটি খ / সি বলে মনে হচ্ছে (আব) ^ 2 = এ ^ 2-বি ^ 2
চার্লস এল

4
@ চার্লসএল .: এটি কাজ করা উচিত, এবং 4 সঠিক উত্তর।
Musiphil

4
@StudentT: না, কিন্তু আপনি প্রতিস্থাপন করতে পারেন (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))...
ম্যাসিফিল

6
std::inner_productবর্গাকার যোগফলের জন্য ব্যবহার করা খুব ঝরঝরে।
পল আর

65

যদি পারফরম্যান্স আপনার পক্ষে গুরুত্বপূর্ণ, এবং আপনার সংকলক ল্যাম্বডাসকে সমর্থন করে তবে স্টাডিভ গণনাটি দ্রুত এবং সহজতর করা যেতে পারে: ভিএস ২০১২ এর সাথে পরীক্ষাগুলিতে আমি খুঁজে পেয়েছি যে নির্বাচিত উত্তরে প্রদত্ত বুস্ট কোডের চেয়ে নীচের কোডটি 10 ​​এক্স এর বেশি দ্রুত ; এটি ম্যাসিফিল দ্বারা প্রদত্ত স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে উত্তরের নিরাপদ সংস্করণের চেয়ে 5 এক্স দ্রুত।

দ্রষ্টব্য আমি নমুনা স্ট্যান্ডার্ড বিচ্যুতি ব্যবহার করছি, তাই নীচের কোডটি কিছুটা আলাদা ফলাফল দেয় ( স্ট্যান্ডার্ড বিচ্যুতির ক্ষেত্রে একটি বিয়োগ কেন আছে )

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));

এই উত্তরটি ভাগ করে নেওয়ার জন্য এক বছর পরেও ধন্যবাদ। এখন আমি আরও এক বছর পরে আসছি এবং মান ধরণের এবং ধারক উভয় প্রকারের জন্য এটি একটি জেনেরিক তৈরি করেছি। এখানে দেখুন (দ্রষ্টব্য: আমি অনুমান করি যে লুপের জন্য আমার পরিসীমা-ভিত্তিক আপনার
ল্যাম্বদা

4
v.end () এর পরিবর্তে std :: end (v) ব্যবহারের মধ্যে পার্থক্য কী?
স্পুরা

4
std::end()ফাংশন ক্ষেত্রে জন্য সি ++ 11 মান দ্বারা যোগ করা হয়েছিল যখন মত কিছুই আছে v.end()std::endকম মান ধারক জন্য ওভারলোড করা যেতে পারে - দেখুন en.cppreference.com/w/cpp/iterator/end
pepr

কেন আপনি দ্রুত ব্যাখ্যা করতে পারেন?
ডিভ_নাট

4
ভাল একটি জিনিসের জন্য, "নিরাপদ" উত্তর (যা আমার উত্তরের মতো) অ্যারে দিয়ে 3 টি পাস করে: একবার যোগফলের জন্য, একবার ডিফারেন্ট-এর জন্য এবং একবার স্কোয়ারিংয়ের জন্য। আমার কোডে মাত্র 2 টি পাস - এটি দ্বিতীয় দুটি পাসকে একটিতে বিভক্ত করছে। এবং (যখন আমি সর্বশেষে দেখেছি, এখন বেশ কিছুক্ষণ আগে!) অভ্যন্তরীণ_রকমের কলগুলি অপরিবর্তিত হয়নি। এছাড়াও "নিরাপদ" কোডটি সম্পূর্ণ ভিন্ন নতুন অ্যারেগুলিতে ভিফ অনুলিপি করে, যা আরও বিলম্বিত করে। আমার মতে আমার
কোডটিও

5

ম্যাসিফিল দ্বারা উত্তরের উন্নতি করে , আপনি diffকেবল অস্থায়ী ভেক্টর ছাড়াই একটি স্ট্যান্ডার্ড বিচ্যুতি ফাংশন লিখতে পারেন , কেবল inner_productসি ++ 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 ));
}

আমি সন্দেহ করি যে অতিরিক্ত মধ্যবর্তী স্টোরেজটি ব্যবহারের চেয়ে একাধিকবার বিয়োগ করা কম দামের এবং আমি মনে করি এটি আরও পাঠযোগ্য, তবে আমি এখনও সম্পাদনটি পরীক্ষা করে দেখিনি।


4
আমি মনে করি এটি প্রমিতের বিচ্যুতি নয়, প্রকরণটি গণনা করছে।
সাগ_মান

স্ট্যান্ড ডেভিয়েশন এন -1 দ্বারা নয়, এন দ্বারা বিভাজক গণনা করা হয়। আপনি ফান.সাইজ () - 1 দিয়ে স্কো_সামকে ভাগ করবেন কেন?
পজক জোক :12

আমি "সংশোধিত স্ট্যানডার্ড ডেভিয়েশন" (দেখুন উদাঃ কম্পিউটিং করছি en.wikipedia.org/wiki/... )
codeling

2

দেখে মনে হচ্ছে এটি নীচের মার্জিত পুনরাবৃত্ত সমাধান সমাধান করা হয় নি, যদিও এটি দীর্ঘ সময় ধরে ছিল। নুথের আর্ট অফ কম্পিউটার প্রোগ্রামিংকে উল্লেখ করে,

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)). 

আশাকরি এটা সাহায্য করবে!


1

আমার উত্তর জোশ গ্রিফারের মতো তবে একই সাথে সাধারণভাবে প্রচার করা হয়েছে ov নমুনা বৈকল্পিক মাত্র নমুনা covarانس হয় তবে দুটি ইনপুট একই। এর মধ্যে বেসেলের পারস্পরিক সম্পর্ক রয়েছে।

    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);
    }

0

পূর্বে উল্লিখিত সংস্করণগুলির চেয়ে 2x দ্রুত - বেশিরভাগ কারণ রূপান্তর () এবং অভ্যন্তরীণ_প্রডাক্ট () লুপগুলি যোগদান করেছে। আমার শর্টকাট / টাইপিডস / ম্যাক্রো সম্পর্কে দুঃখিত: ফ্লো = ফ্লোট। সিআর কনস্ট রেফ ভিএফ্লো - ভেক্টর ভিএস2010-এ পরীক্ষিত

#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; } ?
এলফেন শিশির

4
হ্যাঁ সি ++ 11 এ। ম্যাক্রোগুলি ব্যবহার করার চেষ্টা করছে যা এটির সংস্করণটিকে স্বাধীন করে তুলবে। কোড আপডেট করেছে। পুনশ্চ. পাঠযোগ্যতার জন্য আমি সাধারণত এলওসি-তে 1 টি ক্রিয়া পছন্দ করি। সংকলকটি দেখতে পাবে যে এগুলি ধ্রুব পুনরাবৃত্তি এবং এটি একবারে পুনরাবৃত্তি করা আরও দ্রুত "যদি" মনে করে তবে তাদের সাথে যোগ দিন। এটি ছোট ছোট পদক্ষেপে করা (স্ট্যান্ড :: অভ্যন্তরীণ_প্রডक्ट () ব্যবহার না করে, যেমন একজাতীয়-স্টাইল) নতুন পাঠককে এর অর্থ কী তা ব্যাখ্যা করে। বাইনারি পার্শ্ব প্রতিক্রিয়া দ্বারা ছোট হবে (কিছু ক্ষেত্রে)।
slyy2048

"ব্যবহার ম্যাক্রো যে এটা সংস্করণ স্বাধীন করার চেষ্টা করছেন" - এখনো কনস্ট্রাক্ট ( "প্রতিটি জন্য" অ-মানক ভিসুয়াল সি ++ নিজেকে সীমাবদ্ধ stackoverflow.com/questions/197375/... )
codeling

-3

আপনার নিজস্ব ধারক তৈরি করুন:

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();
        }
};

এটির কিছু সীমাবদ্ধতা রয়েছে তবে আপনি কী করছেন জানেন যখন এটি সুন্দরভাবে কাজ করে।


4
প্রশ্নের উত্তর দিতে: কারণ একেবারেই দরকার নেই। বিনামূল্যে ফাংশন লেখার তুলনায় আপনার নিজের ধারক তৈরির কোনও লাভ নেই।
কনরাড রুডল্ফ

4
এটি দিয়ে কোথায় শুরু করব তাও আমি জানি না। আপনি অন্তর্নিহিত ডেটা স্ট্রাকচার হিসাবে একটি তালিকা ব্যবহার করছেন, আপনি মানগুলিও ক্যাশে করবেন না, যা আমি ধারক-জাতীয় কাঠামোটি ব্যবহার করার জন্য ভাবতে পারি এমন কয়েকটি কারণগুলির মধ্যে একটি। বিশেষত যদি মানগুলি মাঝে মাঝে সুযোগ পায় এবং গড় / স্টডিডিভের প্রায়শই প্রয়োজন হয়।
তৈরি করুন

-7

// এর অর্থ সি ++ এ বিচ্যুতি

/ একটি বিচ্যুতি যা একটি পর্যবেক্ষণ করা মান এবং স্বার্থের পরিমাণের প্রকৃত মূল্যের মধ্যে পার্থক্য (যেমন একটি জনসংখ্যার অর্থ) একটি ত্রুটি এবং এমন একটি বিচ্যুতি যা পর্যবেক্ষণকৃত মান এবং সত্য মানের একটি অনুমানের মধ্যে পার্থক্য (যেমন অনুমান একটি নমুনা গড় হতে পারে) একটি অবশিষ্টাংশ। এই ধারণাগুলি পরিমাপের ব্যবধান এবং অনুপাত স্তরের ডেটার জন্য প্রযোজ্য। /

#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;

}

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.