我们得到这些包含16字节代码的~50GB数据文件,我希望找到任何时间的1/2%或更多的代码。有什么方法可以一次性通过数据吗?
编辑:有大量代码 - 每个代码都可能不同。
EPILOGUE:我选择Darius Bacon作为最佳答案,因为我认为最好的算法是对他所关联的多数元素的修改。大多数算法应该是可修改的,只能使用少量的内存 - 比如201代码,我认为会得到1/2%。基本上你只需要在流中计算最多201个不同的代码。一旦找到201个不同的代码,就会丢弃每个代码中的一个(从计数器中扣除1,忘记任何变为0的代码)。最后,你最多下降了N / 201次,所以任何出现次数超过的代码都必须在那里。
但这是一个两遍算法,而不是一个。你需要第二次通过计算候选人的数量。实际上很容易看出,这个问题的任何解决方案都必须使用至少2次传递(你加载的第一批元素可能都不同,其中一个代码最终可能只有1/2%)
感谢您的帮助!
答案 0 :(得分:13)
Metwally et al., Efficient Computation of Frequent and Top-k Elements in Data Streams (2005)。我在雅虎读到的一些其他相关论文是我现在找不到的;但这看起来是一个好的开始。
编辑:啊,请看Brian Hayes article。由于Demaine等人的参考,它绘制了一个精确的算法。它只需很少的记忆即可完成,并产生一系列项目,包括您正在寻找的常用项目(如果存在的话)。获得准确的计数需要(现在可以处理的)第二遍。
答案 1 :(得分:3)
这将取决于代码的分布。如果有足够多的不同代码,您可以使用地图在核心中构建http://en.wikipedia.org/wiki/Frequency_distribution。否则你可能需要构建一个http://en.wikipedia.org/wiki/Histogram,然后对检查每个桶中代码频率的数据进行多次传递。
答案 2 :(得分:2)
在内存中对文件的块进行排序,就像您正在执行和外部排序一样。但是,您可以只编写每个不同的代码以及该块中出现的次数,而不是写出每个块中的所有已排序代码。最后,合并这些摘要记录以查找每个代码的出现次数。
此过程可扩展到任何大小的数据,并且只对输入数据进行一次传递。可能需要多次合并传递,具体取决于您希望一次打开多少个摘要文件。
对文件进行排序可以使用固定数量的内存计算每个代码的出现次数,无论输入大小如何。
您还知道代码总数(通过将输入大小除以固定代码大小,或通过计算排序过程中可变长度代码的数量来解决更常见的问题)。
因此,您知道与每个代码关联的输入的比例。
这基本上就是管道sort * | uniq -c
如果每个代码只出现一次,那就没问题了;你只需要能够计算它们。
答案 3 :(得分:1)
这取决于存在多少不同的代码,以及您可用的内存量。
我的第一个想法是建立一个计数器的哈希表,代码作为键。循环遍历整个文件,增加相应代码的计数器,并计算总数。最后,使用超过(*总计数器1/200)的计数器过滤所有键。
答案 4 :(得分:1)
如果文件只包含16字节代码,并且您知道每个文件的大小,则可以计算每个文件中的代码数。然后你可以找到0.5%的阈值,并按照任何其他建议来计算每个代码的出现次数,记录每个代码的频率超过阈值。
答案 5 :(得分:1)
每个文件的内容是代表单个数据集,还是文件之间有任意截断?在后一种情况下,假设代码随时间分布不变,您可以通过将每个文件拆分为更小,更易于管理的块来简化您的生活。作为奖励,您可以更快地获得初步结果,然后可以更早地进入下一个流程。