我有一大堆数字,可能在几千兆字节范围内。第一个问题是我无法将所有这些存储在内存中。其次是任何添加这些的尝试都会导致溢出。我在考虑使用更多的滚动平均值,但它需要准确。有什么想法吗?
这些都是浮点数。
这不是从数据库中读取的,而是从多个来源收集的CSV文件。它必须准确,因为它存储为秒的一部分(例如; 0.293482888929),滚动平均值可以是.2和.3之间的差异
这是一组代表用户响应某些表单操作的时间。例如,在显示消息框时,按“确定”或“取消”需要多长时间。数据发送给我存储为秒。部分秒;例如1.2347秒。将它转换为毫秒,我溢出int,long等等。相当快。即使我不转换它,我仍然会很快溢出它。我想下面的一个答案是正确的,也许我不必100%准确,只要在一个特定的StdDev中的某个范围内查看,我就足够了。
答案 0 :(得分:18)
您可以从您的集合中随机抽样(“population”)以获得平均值(“mean”)。准确度将取决于样本的变化程度(由“standard deviation”或方差确定)。
优点是你有数十亿的观察结果,你只需要对它们中的一小部分进行采样,以获得不错的准确度或你选择的“confidence range”。如果条件合适,这会减少你将要做的工作量。
这是C#的numerical library,包括随机序列生成器。只需创建一个随机的数字序列,引用元素数组中的索引(从1到 x ,数组中的元素数量)。取消引用以获取值,然后计算您的平均值和标准差。
如果您想测试数据的分布,请考虑使用Chi-Squared Fit测试或K-S测试,您可以在许多电子表格和统计数据包中找到它(例如{{3} })。这将有助于确认这种方法是否可用。
答案 1 :(得分:13)
整数还是花车?
如果它们是整数,则需要通过读取数字并记录您看到的每个值的数量来累积频率分布。这很容易平均化。
对于浮点,这有点问题。鉴于浮动的总体范围和实际分布,您必须计算出一个bin大小,以保留您想要的精度而不保留所有数字。
修改强>
首先,您需要对数据进行采样以获得均值和标准差。几千点应该足够好了。
然后,您需要确定一个可敬的范围。人们在平均值周围选择±6σ(标准偏差)之类的东西。您可以将此范围划分为尽可能多的铲斗。
实际上,存储桶的数量决定了平均值中的有效位数。因此,选择10,000或100,000个桶来获得4或5位精度。由于这是一种测量,因此您的测量只有两位或三位数的几率很高。
修改强>
您将发现的是,您的初始样本的平均值非常接近任何其他样本的平均值。任何样本均值接近人口均值。你会注意到你的大多数(但不是全部)手段彼此之间有1个标准差。
您应该发现测量误差和误差大于标准偏差。
这意味着样本均值与总体均值一样有用。
答案 2 :(得分:9)
滚动平均值不会像其他任何东西一样准确(折扣舍入错误,我的意思)?由于所有分裂,它可能有点慢。
您可以对批量数字进行分组并递归地对其进行平均。像平均100个数字100次,然后平均结果。这可能会减少骚扰,而且大部分都会增加。
实际上,如果你一次添加256或512,你可以将结果按8位或9位移位(我相信你可以通过简单地改变浮点尾数来做到这一点) - 这将使你的程序非常快,它可以只用几行代码递归写入(不计算尾数移位的不安全操作)。
也许除以256会使用这种优化?我可能要加速测试除以255对256,看看是否有一些大的改进。我猜不是。
答案 3 :(得分:7)
您的意思是32位和64位数字。但为什么不只使用一个合适的Rational Big Num库?如果你有这么多数据,并且你想要一个精确的平均值,那么只需编码即可。
class RationalBignum {
public Bignum Numerator { get; set; }
public Bignum Denominator { get; set; }
}
class BigMeanr {
public static int Main(string[] argv) {
var sum = new RationalBignum(0);
var n = new Bignum(0);
using (var s = new FileStream(argv[0])) {
using (var r = new BinaryReader(s)) {
try {
while (true) {
var flt = r.ReadSingle();
rat = new RationalBignum(flt);
sum += rat;
n++;
}
}
catch (EndOfStreamException) {
break;
}
}
}
Console.WriteLine("The mean is: {0}", sum / n);
}
}
请记住,那里有比你的编译器提供给你更多的数字类型。
答案 4 :(得分:5)
你可以将数据分成1000组数字,平均数,然后平均数。
答案 5 :(得分:4)
这是一个典型的分而治之的问题。
问题在于大量数字的平均值是相同的 作为集合的前半部分的平均值,与集合的后半部分的平均值平均。
换句话说:
AVG(A[1..N]) == AVG( AVG(A[1..N/2]), AVG(A[N/2..N]) )
这是一个简单的C#递归解决方案。 它通过了我的测试,应该是完全正确的。
public struct SubAverage
{
public float Average;
public int Count;
};
static SubAverage AverageMegaList(List<float> aList)
{
if (aList.Count <= 500) // Brute-force average 500 numbers or less.
{
SubAverage avg;
avg.Average = 0;
avg.Count = aList.Count;
foreach(float f in aList)
{
avg.Average += f;
}
avg.Average /= avg.Count;
return avg;
}
// For more than 500 numbers, break the list into two sub-lists.
SubAverage subAvg_A = AverageMegaList(aList.GetRange(0, aList.Count/2));
SubAverage subAvg_B = AverageMegaList(aList.GetRange(aList.Count/2, aList.Count-aList.Count/2));
SubAverage finalAnswer;
finalAnswer.Average = subAvg_A.Average * subAvg_A.Count/aList.Count +
subAvg_B.Average * subAvg_B.Count/aList.Count;
finalAnswer.Count = aList.Count;
Console.WriteLine("The average of {0} numbers is {1}",
finalAnswer.Count, finalAnswer.Average);
return finalAnswer;
}
答案 6 :(得分:3)
诀窍是你担心溢出。在这种情况下,这一切都归结为执行顺序。基本公式是这样的:
鉴于:
下一个平均值(A 1 )是:A = current avg
C = count of items
V = next value in the sequence
(C * A) + V A1 = ——————————— C + 1
危险在于,您担心在评估序列的过程中,A
应保持相对可控性,C会变得非常大。
最终C * A将溢出整数或双精度类型。
我们可以尝试的一件事就是像这样重写它,以减少溢出的可能性:
A1 = C/(C+1) * A/(C+1) + V/(C+1)
通过这种方式,我们永远不会乘以C * A而只处理较小的数字。但现在关注的是分工操作的结果。如果C非常大,则C/C+1
(例如)在约束到正常浮点表示时可能没有意义。我能建议的最好是在这里使用C的最大类型。
答案 7 :(得分:2)
这是在伪代码中执行此操作的一种方法:
average=first count=1 while more: count+=1 diff=next-average average+=diff/count return average
答案 8 :(得分:1)
对于迟到的评论感到抱歉,但是Joel Coehoorn提供的上述公式是不是错误地重写了?
我的意思是,基本公式是正确的:
假设:
A =当前平均值 C =项目数 V =序列中的下一个值
下一个平均值(A1)是:
A1 =((C * A)+ V)/(C + 1)
但不是:
我们不应该:A1 = C /(C + 1)* A /(C + 1)+ V /(C + 1)
A1 = C /(C + 1)* A + V /(C + 1)
这可以解释kastermester的帖子:
“我的数学在这里结束 - 你有C,你说”走向无限“或者至少是一个非常大的数字,然后:C /(C + 1)走向1. A /(C + 1 )朝着0. V /(C + 1)走向0.总而言之:A1 = 1 * 0 + 0所以很快就把A1推向0 - 似乎有点偏了。 - kastermester“
因为我们有A1 = 1 * A + 0,即A1走向A,这是正确的。
我一直在使用这种方法长时间计算平均值,上述精度问题对我来说从来都不是问题。
答案 9 :(得分:0)
根据数字的范围,最好有一个数组,其中下标是你的数字,值是这个数字的数量,你可以从这个计算
答案 10 :(得分:0)
如果数字是int,则累计总数为long。如果数字很长......你用的语言是什么?在Java中,您可以在BigInteger中累积总数,BigInteger是一个整数,它将增长到需要的大小。您可以随时编写自己的类来重现此功能。它的要点只是制作一个整数数组来保存每个“大数字”。添加两个数字时,从低位值开始循环。如果加法结果设置了高位,则清除该位并将该位移到下一列。
另一种选择是一次找到1000个数字的平均值。保持这些中间结果,然后当你完成它们的所有平均值时。
答案 11 :(得分:0)
为什么浮点数的总和溢出?为了实现这一点,您需要使值接近最大浮点值,这听起来很奇怪。
如果你正在处理整数,我建议使用BigInteger,或者将集合分成多个子集,递归地平均子集,然后对平均值求平均值。
如果你正在处理花车,那会有点奇怪。滚动平均值可能变得非常不准确。我建议使用滚动平均值,只有在遇到溢出异常或集合结束时才会更新。因此,有效地将集合划分为非溢出集。
答案 12 :(得分:0)
我的两个想法:
答案 13 :(得分:0)
为什么不在计算平均值之前缩放数字(下)?