4

(不是严格意义上的编程,而是程序员需要回答的一个问题。)

我有一个基准X,它由许多子基准x 1 .. x n组成。这是一个相当嘈杂的测试,结果变化很大。为了准确地进行基准测试,我必须减少“可变性”,这需要我首先测量可变性。

我可以使用标准偏差或方差轻松计算每个子基准的可变性。但是,我想得到一个将整体可变性表示为单个数字的数字。

我自己对这个问题的尝试是:

sum = 0
foreach i in 1..n
   calculate mean across the 60 runs of x_i
   foreach j in 1..60
       sum += abs(mean[i] - x_i[j])
variability = sum / 60
4

5 回答 5

2

最好的主意:一旦它达到公开测试版(一周内),就在 Stack Exchange 上询问统计信息。

同时:您实际上可能对可变性的极端更感兴趣,而不是集中趋势(均值等)。对于许多应用程序,我认为通过增加典型用户体验可以获得相对较少的收益,但通过改善最差的用户体验可以获得很多。尝试标准偏差的第 95 个百分位并努力减少它。或者,如果您想要减少典型的可变性请将标准偏差全部绘制在一起。如果它们大致呈正态分布,我不知道你为什么不能取平均值。

于 2010-07-23T05:26:44.330 回答
1

我认为你误解了标准差——如果你运行 50 次测试并有 50 次不同的运行时间,标准差将是一个数字,它描述了这 50 个数字围绕你的平均值分布的紧密或松散程度。结合您的平均运行时间,标准偏差将帮助您了解结果的分布程度。

考虑以下运行时间:

12 15 16 18 19 21 12 14

这些运行时间的平均值是15.875。该集合的样本标准差为 3.27。对 3.27 的实际含义有一个很好的解释(在正态分布的总体中,大约 68% 的样本将落在平均值的一个标准差内:例如,介于15.875-3.27和之间15.875+3.27)但我认为您只是在寻找一种量化的方法结果在您的平均值附近有多“紧密”或“分散”。

现在考虑一组不同的运行时间(例如,在你用 编译所有测试之后-O2):

14 16 14 17 19 21 12 14

这些运行时间的平均值也是15.875. 该集合的样本标准差为 3.0。(因此,大约 68% 的样本将属于15.875-3.015.875+3.0。)这组比第一组更紧密地分组。

你有一个数字来总结一组数字在均值附近的紧凑或松散程度。

注意事项

标准差建立在正态分布的假设之上——但您的应用程序可能不是正态分布的,因此请注意,标准差最多可能只是一个粗略的指导。在直方图中绘制您的运行时间,以查看您的数据是否看起来大致正常或统一或多模式或......

另外,我使用的是样本标准差,因为这些只是基准运行总体空间中的一个样本。我不是专业的统计学家,所以即使是这个基本假设也可能是错误的。如果您坚持样本或总体,总体标准差或样本标准差都会在您的应用程序中为您提供足够好的结果。不要将两者混为一谈。

我提到标准差与平均值一起有助于你理解你的数据:如果标准差几乎和你的平均值一样大,或者更糟,更大,那么你的数据非常分散,也许你的过程不是很可重复. 3%正如您所认识到的,在面对较大的标准偏差时解释加速几乎是无用的。标准偏差大小的最佳判断(根据我的经验)是平均值的大小。

最后说明:是的,您可以手动计算标准差,但是在前十个左右之后就很乏味了。最好使用电子表格或 wolfram alpha 或方便的高中计算器。

于 2010-07-22T10:25:26.523 回答
1

方差:“总组的方差等于子组方差的均值加上子组均值的方差。” 我不得不读了好几遍,然后运行它:这个公式中的 464 == 464,所有数据的标准偏差——你想要的单个数字。

#!/usr/bin/env python
import sys
import numpy as np

N = 10
exec "\n".join( sys.argv[1:] )  # this.py N= ...
np.set_printoptions( 1, threshold=100, suppress=True )  # .1f
np.random.seed(1)

data = np.random.exponential( size=( N, 60 )) ** 5  # N rows, 60 cols
row_avs = np.mean( data, axis=-1 )  # av of each row
row_devs = np.std( data, axis=-1 )  # spread, stddev, of each row about its av
print "row averages:", row_avs
print "row spreads:", row_devs
print "average row spread: %.3g" % np.mean( row_devs )

# http://en.wikipedia.org/wiki/Variance:
# variance of the total group
# = mean of the variances of the subgroups  +  variance of the means of the subgroups
avvar = np.mean( row_devs ** 2 )
varavs = np.var( row_avs )
print "sqrt total variance: %.3g = sqrt( av var %.3g + var avs %.3g )" % (
    np.sqrt( avvar + varavs ), avvar, varavs)

var_all = np.var( data )  # std^2 all N x 60 about the av of the lot
print "sqrt variance all: %.3g" % np.sqrt( var_all )

row averages: [  49.6  151.4   58.1   35.7   59.7   48.   115.6   69.4  148.1   25. ]
row devs: [ 244.7  932.1  251.5   76.9  201.1  280.   513.7  295.9  798.9  159.3]
average row dev: 375
sqrt total variance: 464 = sqrt( av var 2.13e+05 + var avs 1.88e+03 )
sqrt variance all: 464


要查看组方差如何增加,请运行 Wikipedia Variance 中的示例。说我们有

60 men of heights 180 +- 10, exactly 30: 170 and 30: 190  
60 women of heights 160 +- 7, 30: 153 and 30: 167.  

平均标准开发是 (10 + 7) / 2 = 8.5 。虽然在一起,高度

-------|||----------|||-|||-----------------|||---
       153          167 170                 190

传播像 170 +- 13.2,远大于 170 +- 8.5。
为什么 ?因为我们不仅有男性 +- 10 和女性 +- 7 的价差,而且还有从 160 / 180 到共同平均值 170的价差。
练习:用两种方法计算价差 13.2,根据上面的公式,直接计算。

于 2010-07-27T12:49:17.273 回答
0

这是一个棘手的问题,因为基准无论如何都可以具有不同的自然长度。因此,您需要做的第一件事是将每个单独的子基准数据转换为比例不变的值(例如,相对于某些认为良好的基线的“加速因子”),以便您至少有机会比较不同的基准。

然后你需要选择一种方法来组合这些数字。某种平均水平。然而,有许多类型的平均值。我们可以在这里拒绝使用众数和中位数;他们丢弃了太多相关信息。但是不同类型的平均值很有用,因为它们赋予异常值权重的方式不同。我曾经知道(但忘记了)在实践中最有用的是几何平均值还是调和平均值(算术平均值在这里不太好)。几何平均值基本上是对数域中的算术平均值,调和平均值同样是倒数域中的算术平均值。(电子表格使这变得微不足道。)

既然您有一种方法可以将运行基准套件的值组合成适当的信息,那么您必须进行大量运行。您可能希望在您继续执行其他任务时让计算机执行此操作。:-) 然后尝试以各种方式组合这些值。特别是,查看各个子基准的方差和组合基准数的方差。还可以考虑在对数和倒数域中进行一些分析。

请注意,这是一项缓慢的业务,很难正确处理,而且通常无法启动。基准测试只对基准测试中的内容进行性能测试,而这主要不是人们使用代码的方式。最好考虑对您的基准测试工作进行严格的时间限制,而不是关注用户是否认为软件被认为足够快,或者在部署过程中是否实际达到了所需的事务率(有许多非编程方法可以搞砸)。

祝你好运!

于 2010-07-28T10:17:01.210 回答
-1

您正在尝试解决错误的问题。最好尽量减少它。差异可能是由于缓存。

尝试在 Windows 上使用 SetThreadAffinityMask() 函数在单个(相同)内核上运行代码。

放弃第一次测量。

提高广告优先级。

停止超线程。

如果您有许多条件跳转,则可能会在具有不同输入的调用之间引入明显的差异。(这可以通过为第 i 次迭代提供完全相同的输入来解决,然后比较这些迭代之间的测量时间)。

您可以在这里找到一些有用的提示:http ://www.agner.org/optimize/optimizing_cpp.pdf

于 2010-07-22T19:32:26.747 回答