-
19-09-2019 - |
题
我还没有真正使用过方差计算那么多,而且我不太知道会发生什么。事实上我的数学一点也不好。
我有一个包含 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)) );
我得到了合理的价值吗?
计算有什么问题吗?
解决方案
笔记: 看起来您没有计算方差。
方差是通过从每个元素中减去平均值并计算这些差异的加权和来计算的。
所以你需要做的是:
// 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;
请注意,这是样本方差,当基础分布未知时使用(因此我们假设均匀分布)。
另外,经过一番挖掘后,我发现这不是一个无偏估计器。 沃尔夫勒姆·阿尔法 对此有话要说,但举个例子,当 MATLAB 计算方差,它返回“偏差校正样本方差”。
偏差校正方差可以通过将每个元素除以来获得 size-1
, , 或者:
//Please check that size > 1
variance += (MyArray[i]-mean)*(MyArray[i]-mean)/(size-1);
另请注意,值 mean
保持不变。
其他提示
首先,如果您只是想了解什么是“合理”方差,请记住方差基本上是标准差的平方。标准差粗略地衡量了数据点与其期望值之间的典型距离。
因此,如果您的数据平均值为 4692,并且计算出的方差为 1483780,则意味着您的标准差约为 1218,这表明您的数字往往在 3474 - 5910 范围附近。因此,如果你的数字范围是 0 - 10000,那么这个方差实际上对我来说似乎有点低;但这显然取决于数据的分布。
至于计算本身:您可以在第一次读取数据时使用运行计算来计算方差(您不必提前知道平均值): 韦尔福德法:
初始化 M1 = x1 且 S1 = 0。
对于随后的X,请使用复发公式
MK = MK-1 +(XK-MK-1)/K SK = SK-1 +(XK-MK-1)*(XK-MK)。
对于2≤k≤n,方差的KTH估计值为S2 = SK/(K -1)。
只是为了好玩,稍微不同的路线相同的结果,使用std ::的valarray代替的std ::矢量和(各种)算法:
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()
也许使用不同的公式?
#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
样本方差的计算:
#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);
}
既然你有大量的工作,然后对他们做浮点运算,你可能想要做的一切加倍;这将节省您大量铸件。
使用pow .. 2
计算平方似乎有点笨拙。你可以先计算出你的电话号码,然后通过自身相乘得到一个正方形。
如果你正在做的分裂和感觉需要施放,施放的的操作数的(即分子和/或分母)的两倍,而不是结果。你失去精度,如果你把整数。
我不知道,如果你的方差公式是正确的。你可能想看看维基百科的解释,例如。但我不是数学高手要么,所以我不知道你有一个错误。
由于方差的标准偏差的平方,答复 SO 1174984 应该帮忙。简短的诊断是,你需要计算的值,以及该值的总和的平方和,而你似乎没有那么做。
由于有10个 6 值,任何值的平方可高达10 8 ,你可能最终与正方形的高达10的总和< SUP> 14 ;您的64位整数,最多可存储10 18 ,所以你仍然可以处理一万次一样多的输入,或值范围高达百万,而不是只有一万,没有运行到溢出。有没有迫切需要,因此,移动到纯双计算。