Boost kullanarak numuneler içeren bir vektör için ortalama ve standart sapmayı hesaplamanın bir yolu var mı ?
Yoksa bir akümülatör oluşturup vektörü ona beslemem mi gerekiyor?
Boost kullanarak numuneler içeren bir vektör için ortalama ve standart sapmayı hesaplamanın bir yolu var mı ?
Yoksa bir akümülatör oluşturup vektörü ona beslemem mi gerekiyor?
Yanıtlar:
Akümülatörleri kullanma olduğu anlamına gelir ve standart sapmaları hesaplamak için bir yol 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
yuvarlama hataları nedeniyle varyans çok küçükse yanlış sonuç verecek şekilde tam bir formülle hesaplar . Aslında negatif varyans üretebilir.
Boost'un daha spesifik işlevleri olup olmadığını bilmiyorum, ancak bunu standart kitaplıkla yapabilirsiniz.
Verilen std::vector<double> v
, saf yol budur:
#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);
Bu, çok büyük veya küçük değerler için taşmaya veya yetersizliğe karşı hassastır. Standart sapmayı hesaplamanın biraz daha iyi bir yolu şudur:
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 için GÜNCELLEME :
Çağrı std::transform
, std::minus
ve yerine lambda işlevi kullanılarak yazılabilir std::bind2nd
(artık kullanımdan kaldırılmıştır):
std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; });
mean
üst kısımda hesaplanan değere bağlıdır .
(v.size() - 1)
için v.size()
yukarıdaki son satırında: std::sqrt(sq_sum / (v.size() - 1))
. (İlk yöntem için, biraz karışık bir durum: std::sqrt(sq_sum / (v.size() - 1) - mean * mean * v.size() / (v.size() - 1))
.
std::inner_product
Kareler toplamı için kullanmak çok düzgün.
Performans sizin için önemliyse ve derleyiciniz lambdaları destekliyorsa, stdev hesaplaması daha hızlı ve daha basit yapılabilir: VS 2012 ile yapılan testlerde, aşağıdaki kodun, seçilen yanıtta verilen Boost kodundan 10 kat daha hızlı olduğunu buldum ; ayrıca musiphil tarafından verilen standart kitaplıkları kullanan daha güvenli yanıt sürümünden 5 kat daha hızlıdır.
Not Örnek standart sapma kullanıyorum, bu nedenle aşağıdaki kod biraz farklı sonuçlar veriyor ( Neden Standart Sapmalarda Eksi Bir var )
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()
Gibi bir şey olduğunda işlev durumlar için C ++ 11 standardına göre ilave edilmiştir v.end()
. Daha std::end
az standart konteyner için aşırı yüklenebilir - bkz. En.cppreference.com/w/cpp/iterator/end
Musiphil'in cevabını geliştirerek , geçici vektör olmadan diff
, sadece inner_product
C ++ 11 lambda yetenekleriyle tek bir çağrı kullanarak standart bir sapma işlevi yazabilirsiniz :
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 ));
}
Çıkarma işlemini birden çok kez yapmanın, ek ara depolama kullanmaktan daha ucuz olduğunu düşünüyorum ve daha okunabilir olduğunu düşünüyorum, ancak performansı henüz test etmedim.
Görünüşe göre aşağıdaki zarif özyinelemeli çözüm, uzun zamandır var olmasına rağmen bahsedilmemiştir. Knuth'un Bilgisayar Programlama Sanatına atıfta bulunarak,
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);
daha sonra bir n>=2
değerler listesi için standart sapmanın tahmini şu şekildedir:
stddev = std::sqrt(variance_n / (n-1)).
Bu yardımcı olur umarım!
Cevabım Josh Greifer ile benzer ancak kovaryansı örneklemek için genelleştirilmiştir. Örnek varyansı yalnızca örnek kovaryansıdır, ancak iki giriş aynıdır. Bu, Bessel'in korelasyonunu içerir.
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);
}
Daha önce bahsedilen sürümlerden 2 kat daha hızlı - çoğunlukla transform () ve inner_product () döngüleri birleştirildiği için. Kısayolum / typedefs / makrom için üzgünüm: Flo = float. CR sabit referansı VFlo - vektör. VS2010'da test edildi
#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; }
mi?
Kendi kapsayıcınızı oluşturun:
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();
}
};
Bazı sınırlamaları vardır, ancak ne yaptığınızı bildiğinizde çok güzel çalışır.
// c ++ 'da sapma anlamına gelir
/ Gözlenen bir değer ile bir ilgi miktarının gerçek değeri arasındaki fark olan bir sapma (popülasyon ortalaması gibi), bir hata ve gözlemlenen değer ile gerçek değerin tahmini arasındaki fark olan bir sapmadır (böyle bir tahmin bir örnek ortalama olabilir) bir kalıntıdır. Bu kavramlar, ölçüm aralığı ve oran seviyelerindeki veriler için geçerlidir. /
#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;
}