2

分散計算はあまり使用していませんし、何が期待できるのかよくわかりません。実は私は数学が苦手です。

0〜10000の範囲の1000000個のランダムな数値の配列があります。

配列はさらに大きくなる可能性があるため、合計に64ビット整数を使用します。

分散を計算する方法のコードを見つけようとしましたが、正しい出力が得られるかどうかわかりません。

平均は4692、中央値は4533です。次のコードを使用して分散1483780.469308を取得します。

// size is the element count, in this case 1000000
// value_sum is __int64

double p2 = pow( (double)(value_sum - (value_sum/size)), (double)2.0 );
double variance = sqrt( (double)(p2 / (size-1)) );

妥当な値を取得していますか?

計算に何か問題がありますか?

4

7 に答える 7

5

注:分散を計算しているようには見えません。

分散は、すべての要素から平均を減算し、これらの差の加重和を計算することによって計算されます。

したがって、あなたがする必要があるのは:

// Get mean
double mean = static_cast<double>(value_sum)/size;

// Calculate variance
double variance = 0;
for(int i = 0;i<size;++i) 
{
  variance += (MyArray[i]-mean)*(MyArray[i]-mean)/size;
}

// Display
cout<<variance;

これは標本分散であり、基礎となる分布が不明な場合に使用されることに注意してください(したがって、一様分布を想定しています)。

また、少し掘り下げてみると、これは偏りのない推定量ではないことがわかりました。Wolfram Alphaはこれについて何か言いたいことがありますが、例として、MATLABが分散を計算すると、「バイアス補正されたサンプル分散」が返されます。

size-1バイアス補正された分散は、各要素を、、またはで割ることによって取得できます。

//Please check that size > 1
variance += (MyArray[i]-mean)*(MyArray[i]-mean)/(size-1); 

meanまた、の値は同じままであることに注意してください。

于 2009-11-12T12:58:55.027 に答える
3

まず第一に、「合理的な」分散とは何かを把握しようとしているだけの場合、分散は基本的に標準偏差の2乗であることに注意してください。標準偏差は、データポイントからその期待値までの一般的な距離を大まかに測定します。

したがって、データの平均が4692で、計算された分散が1483780になる場合、これは標準偏差が約1218であることを意味します。これは、数値が3474〜5910の範囲の近くにある傾向があることを示しています。あなたの数の範囲が0-10000の場合、私には少し低いように思えます。しかし、それは明らかにあなたのデータの分布に依存します。

計算自体について:Welfordの方法を使用して、最初にデータを読み取るときに(事前に平均を知る必要はありません)、実行中の計算を使用して分散を計算できます。

M1=x1およびS1=0を初期化します。

後続のxには、繰り返し式を使用します

Mk = Mk-1+(xk-Mk-1)/ k Sk = Sk-1 +(xk-Mk-1)*(xk-Mk)。

2≤k≤nの場合、分散のk番目の推定値はs2 = Sk /(k-1)です。

于 2009-11-12T13:18:14.563 に答える
3

楽しみのために、std ::vectorと(さまざまな)アルゴリズムの代わりにstd :: valarrayを使用して、同じ結果へのわずかに異なるルート:

template <class T>
T const variance(std::valarray<T> const &v) {
    if (v.size() == 0)
        return T(0.0);
    T average = v.sum() / v.size();
    std::valarray<T> diffs = v-average;
    diffs *= diffs;
    return diffs.sum()/diffs.size();
}

ジェイコブが示唆したように、分散計算には実際には2つの可能なバージョンがあります。現状では、これは入力が「ユニバース」であることを前提としています。ユニバース全体のサンプルのみを取得した場合は、最後の行で。(diffs.size()-1)の代わりに:を使用する必要がありdiffs.size()ます。

于 2009-11-12T15:32:06.413 に答える
2

多分別の式を使用しますか?

#include <functional>
#include <algorithm>
#include <iostream>
int main()
{
 using namespace std;

 vector<double> num( 3 );
 num[ 0 ] = 4000.9, num[ 1 ] = 11111.221, num[ 2 ] = -2;


 double mean = std::accumulate(num.begin(), num.end(), 0.0) / num.size();
 vector<double> diff(num.size());
 std::transform(num.begin(), num.end(), diff.begin(), 
                std::bind2nd(std::minus<double>(), mean));
 double variance = std::inner_product(diff.begin(), diff.end(), 
                                     diff.begin(), 0.0) / (num.size() - 1);
 cout << "mean = " << mean << endl
      << "variance = " << variance << endl;
}

出力:平均=5036.71分散=3.16806e + 07

于 2009-11-12T13:01:15.317 に答える
1

分散計算の例:

#include <math.h>
#include <vector>

double Variance(std::vector<double>);

int main()
{
     std::vector<double> samples;
     samples.push_back(2.0);
     samples.push_back(3.0);
     samples.push_back(4.0);
     samples.push_back(5.0);
     samples.push_back(6.0);
     samples.push_back(7.0);

     double variance = Variance(samples);
     return 0;
}

double Variance(std::vector<double> samples)
{
     int size = samples.size();

     double variance = 0;
     double t = samples[0];
     for (int i = 1; i < size; i++)
     {
          t += samples[i];
          double diff = ((i + 1) * samples[i]) - t;
          variance += (diff * diff) / ((i + 1.0) *i);
     }

     return variance / (size - 1);
}
于 2017-03-14T01:09:38.400 に答える
0

多数の数値を処理してから浮動小数点演算を実行しているため、すべてを2倍で実行することをお勧めします。それはあなたに多くのキャストを節約するでしょう。

正方形の計算に使用pow .. 2するのは少し厄介なようです。あなたは最初にあなたの数を計算し、次にそれをそれ自体で掛けて正方形を得ることができます。

除算を行っていて、キャストする必要があると感じた場合は、オペランド(つまり、分子や分母)を結果ではなくdoubleにキャストします。整数を除算すると、精度が低下します。

分散の式が正しいかどうかはわかりません。たとえば、ウィキペディアの説明を見たいと思うかもしれません。しかし、私も数学の専門家ではないので、間違いがあるかどうかはわかりません。

于 2009-11-12T12:58:12.157 に答える
0

分散は標準偏差の2乗であるため、SO1174984の回答が役立つはずです。簡単な診断では、値の2乗の合計と値の合計を計算する必要がありますが、それは行われていないようです。

10 6の値があり、任意の値の2乗は最大10 8になる可能性があるため、最大1014の2乗の合計になる可能性があります。64ビット整数は最大1018を格納できるため、オーバーフローが発生することなく、1万倍の入力、または1万ではなく最大100万の値を処理できます。したがって、純粋な二重計算に移行する緊急の必要はありません。

于 2009-11-12T13:01:36.923 に答える