代码之家  ›  专栏  ›  技术社区  ›  sharkin

用大数计算方差

  •  2
  • sharkin  · 技术社区  · 15 年前

    我真的没有用那么多的方差计算,我也不知道该期待什么。事实上,我数学一点也不好。

    我有一个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 回复  |  直到 8 年前
        1
  •  5
  •   Jacob    15 年前

    注: 看起来你不是在计算方差。

    方差是通过从每个元素中减去平均值并计算这些差异的加权和来计算的。

    所以你需要做的是:

    // 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 保持不变。

        2
  •  3
  •   Dan Tao    15 年前

    首先,如果你只是想弄清楚什么是“合理的”方差,记住方差基本上就是标准方差的平方。标准差粗略地测量数据点到预期值的典型距离。

    所以,如果你的数据的平均值是4692,而你计算出来的方差是1483780,这意味着你的标准差是1218,这意味着你的数字倾向于在3474-5910之间。所以,如果你的数字的范围是0-10000,方差对我来说似乎有点低,但这显然取决于你的数据分布。

    至于计算本身:当您第一次读取数据时(不必事先知道平均值),您可以使用运行计算来计算方差。 Welford's Method :

    初始化m1=x1和s1=0。

    对于后续的X,使用循环 公式

    mk=mk-1+(xk-mk-1)/k sk=sk-1+ (XK-MK-1)*(XK-MK)。

    对于2_k_n,对 方差为s2=sk/(k-1)。

        3
  •  3
  •   Jerry Coffin    15 年前

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

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

        4
  •  2
  •   dirkgently    15 年前

    可能使用不同的公式?

    #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

        5
  •  1
  •   D.Zadravec    8 年前

    样本方差计算:

    #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);
    }
    
        6
  •  0
  •   Carl Smotricz    15 年前

    因为您处理的是大量的数据,然后对它们执行浮点运算,所以您可能希望以双精度形式执行所有操作;这样可以节省大量的强制转换。

    使用 pow .. 2 计算一个正方形似乎有点笨拙。你可以先计算出你的数字,然后再乘以它本身得到一个平方。

    如果你在做除法,觉得有必要投,投 操作数 (即分子和/或分母)加倍而不是结果。如果你分割整数,你就失去了准确性。

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

        7
  •  0
  •   Community CDub    8 年前

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

    既然你有10个 值,任何值的平方都可以达到10 ,你可以得到10个平方和 十四 ;64位整数最多可存储10个 十八 ,因此,您仍然可以处理10000倍的输入,或者最大为100万而不是仅为10000的值,而不会出现溢出。因此,没有迫切需要转移到纯双计算。