2

我并没有真正使用过方差计算,我也不知道会发生什么。其实我对数学一点也不好。

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

数组可能会变得更大,所以我使用 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)) );

我得到了合理的价值吗?

计算有什么问题吗?

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

只是为了好玩,使用 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();
}

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

于 2009-11-12T15:32:06.413 回答
3

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

因此,如果您的数据的平均值为 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 回答
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

由于您正在处理大量数字,然后对它们进行浮点运算,因此您可能希望以双精度形式进行所有操作;这将为您节省大量演员表。

用来pow .. 2计算平方似乎有点尴尬。您可以先计算您的数字,然后将其与自身相乘得到一个平方。

如果您正在做除法并且觉得需要转换,请将操作数(即分子和/或分母)转换为 double 而不是结果。如果你除整数,你会失去准确性。

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

于 2009-11-12T12:58:12.157 回答
0

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

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

于 2009-11-12T13:01:36.923 回答