您好我正在尝试计算一系列整数或浮点数的加权方差和加权标准差。我找到了这些链接:
http://math.tutorvista.com/statistics/standard-deviation.html#weighted-standard-deviation
http://www.itl.nist.gov/div898/software/dataplot/refman2/ch2/weightsd.pdf(警告pdf)
到目前为止,这是我的模板功能。方差和标准差工作正常,但对于我的生活,我无法让加权版本与 pdf 底部的测试用例相匹配:
template <class T>
inline float Mean( T samples[], int count )
{
float mean = 0.0f;
if( count >= 1 )
{
for( int i = 0; i < count; i++ )
mean += samples[i];
mean /= (float) count;
}
return mean;
}
template <class T>
inline float Variance( T samples[], int count )
{
float variance = 0.0f;
if( count > 1 )
{
float mean = 0.0f;
for( int i = 0; i < count; i++ )
mean += samples[i];
mean /= (float) count;
for( int i = 0; i < count; i++ )
{
float sum = (float) samples[i] - mean;
variance += sum*sum;
}
variance /= (float) count - 1.0f;
}
return variance;
}
template <class T>
inline float StdDev( T samples[], int count )
{
return sqrtf( Variance( samples, count ) );
}
template <class T>
inline float VarianceWeighted( T samples[], T weights[], int count )
{
float varianceWeighted = 0.0f;
if( count > 1 )
{
float sumWeights = 0.0f, meanWeighted = 0.0f;
int numNonzero = 0;
for( int i = 0; i < count; i++ )
{
meanWeighted += samples[i]*weights[i];
sumWeights += weights[i];
if( ((float) weights[i]) != 0.0f ) numNonzero++;
}
if( sumWeights != 0.0f && numNonzero > 1 )
{
meanWeighted /= sumWeights;
for( int i = 0; i < count; i++ )
{
float sum = samples[i] - meanWeighted;
varianceWeighted += weights[i]*sum*sum;
}
varianceWeighted *= ((float) numNonzero)/((float) count*(numNonzero - 1.0f)*sumWeights); // this should be right but isn't?!
}
}
return varianceWeighted;
}
template <class T>
inline float StdDevWeighted( T samples[], T weights[], int count )
{
return sqrtf( VarianceWeighted( samples, weights, count ) );
}
测试用例:
int samples[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23 };
printf( "%.2f\n", StdDev( samples, 9 ) );
int weights[] = { 1, 1, 0, 0, 4, 1, 2, 1, 0 };
printf( "%.2f\n", StdDevWeighted( samples, weights, 9 ) );
结果:
7.46
1.94
应该:
7.46
5.82
我认为问题在于加权方差有几种不同的解释,我不知道哪个是标准的。我发现了这种变化:
http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Weighted_incremental_algorithm
template <class T>
inline float VarianceWeighted( T samples[], T weights[], int count )
{
float varianceWeighted = 0.0f;
if( count > 1 )
{
float sumWeights = 0.0f, meanWeighted = 0.0f, m2 = 0.0f;
for( int i = 0; i < count; i++ )
{
float temp = weights[i] + sumWeights,
delta = samples[i] - meanWeighted,
r = delta*weights[i]/temp;
meanWeighted += r;
m2 += sumWeights*delta*r; // Alternatively, m2 += weights[i] * delta * (samples[i]−meanWeighted)
sumWeights = temp;
}
varianceWeighted = (m2/sumWeights)*((float) count/(count - 1));
}
return varianceWeighted;
}
结果:
7.46
5.64
我还尝试查看 boost 和 esutil 但它们并没有太大帮助:
http://www.boost.org/doc/libs/1_48_0/boost/accumulators/statistics/weighted_variance.hpp http://esutil.googlecode.com/svn-history/r269/trunk/esutil/stat/util.py
我不需要整个统计库,更重要的是,我想了解实现。
有人可以发布函数来正确计算这些吗?
如果您的函数可以一次性完成,则可以加分。
另外,有谁知道加权方差是否与具有重复值的普通方差给出相同的结果?例如,samples[] = { 1, 2, 3, 3 } 的方差是否与 samples[] = { 1, 2, 3 }, weights[] = { 1, 1, 2 } 的加权方差相同?
更新:这是我为探索问题而设置的谷歌文档电子表格。不幸的是,我的答案与 NIST pdf 相去甚远。我认为问题出在 unbias 步骤中,但我不知道如何解决它。
https://docs.google.com/spreadsheet/ccc?key=0ApzPh5nRin0ldGNNYjhCUTlWTks2TGJrZW4wQUcyZnc&usp=sharing
结果是加权方差为 3.77,这是我在 c++ 代码中得到的加权标准差 1.94 的平方。
我正在尝试在我的 Mac OS X 设置上安装 octave,以便我可以使用权重运行他们的 var() 函数,但是使用 brew 安装它需要很长时间。我现在很喜欢刮牦牛毛。