用大数计算方差

时间:2009-11-12 12:51:34

标签: c++ math statistics largenumber variance

我还没有真正使用方差计算那么多,我不知道会发生什么。实际上我对数学一点都不太好。

我有一个1000000随机数值的数组,范围是0-10000。

数组可能会变得更大,所以我使用64位int作为总和。

我试图找到关于如何计算方差的代码,但我不知道我是否得到了正确的输出。

平均值为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)) );

我得到了合理的价值吗?

计算有什么问题吗?

7 个答案:

答案 0 :(得分: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的值保持不变。

答案 1 :(得分:3)

首先,如果您只想了解什么是“合理的”方差,请记住方差基本上是标准偏差的平方。标准差粗略地测量从数据点到其预期值的典型距离。

因此,如果您的数据具有平均值4692,并且您的计算方差为1483780,则表示您的标准偏差约为1218,这表明您的数字往往在3474 - 5910范围附近。所以如果您的数字范围是0 - 10000,那么对我来说这种差异实际上似乎有点低;但它显然取决于您的数据分布。

关于计算本身:您可以使用正在计算的方差来计算方差,因为您第一次使用Welford's Method读取数据(您不必事先知道平均值):< / p>

  

初始化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)。

答案 2 :(得分:3)

只是为了好玩,使用std :: valarray而不是std :: vector和(各种)算法的相同结果略有不同:

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

正如雅各布暗示的那样,实际上有两种可能的方差计算版本。就目前而言,这假设您的输入是“宇宙”。如果您只采用整个Universe的示例,则最后一行应使用:(diffs.size()-1)而不是diffs.size()

答案 3 :(得分: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     variance = 3.16806e + 07

答案 4 :(得分: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);
}

答案 5 :(得分:0)

由于您正在使用大数字然后对它们执行浮点运算,因此您可能希望在双精度数中执行所有操作;这会为你节省很多演员。

使用pow .. 2来计算正方形似乎有点尴尬。你可以先计算你的数字,然后将它自己乘以得到一个正方形。

如果你正在进行划分并感觉需要施放,则将操作数(即分子和/或分母)转换为加倍而不是结果。如果划分整数,则会失去准确性。

我不确定你的方差公式是否正确。例如,您可能想查看维基百科中的解释。但我也不是数学专家,所以我不确定你是否有错误。

答案 6 :(得分:0)

由于方差是标准差的平方,因此SO 1174984的答案应该会有所帮助。简短的诊断是你需要计算值的平方和以及值的总和,而你似乎没有这样做。

由于你有10个 6 值,并且任何值的平方可以达到10 8 ,你最终可能得到一个最大为10的平方和SUP> 14 ;你的64位整数最多可以存储10个 18 ,所以你仍然可以处理一万倍的输入,或者数值高达一百万而不是一万,而不会遇到溢出。因此,没有迫切需要转向纯粹的双重计算。