心理调试:您输入文件实际上是单行线,包含所有的n-gram。所以,当你这样做:
for line in myfile:
c.update(line.split())
它实际上读取整个文件作为一个单一的“线”,然后将其拆分成所有的n-gram的list
。问题是,这意味着存储所有的n-gram的个别副本暂时他们在Python获得去重复-ED在Counter
(三个字母的ASCII str
前3.5 x64的使用〜52个字节,加上参考其他8个字节的巨大存储成本在list
;如果你读了一行699 MB的三字母字符串,每个字符串之间有一个空格,然后分割它,你将产生约1.83亿个字符串,这意味着一个粗略的下界内存使用量为183000000 * 60或大约10GB内存,32位机器的成本较低,但不超过50%(可能更少);在32位机器上,您没有足够的虚拟机以存储5 GB内存地址空间(大多数32台机器被限制为2 GB)。
的最简单的解决将文件拆分为将每个ngram放在自己的行上(或将每行的ngram数限制为合理的数量)。例如,tr
(类UNIX的机器),转换很简单:
tr ' ' '\n' <Output.txt> OutputNewlines.txt
类似的方法可以与发现许多文本编辑器中使用/替换。
如果这不是一种选择,你要通过明确块读取块,而不是行由行,最后空间之前处理所有的东西,节省剩下,然后读取另一个块。
from functools import partial
c = Counter()
with open('Output.txt') as myfile:
remainder = ''
# Read file by fixed size blocks, not lines, assuming no ngram is larger than 8192
for block in iter(partial(myfile.read, 8192), ''):
# Split off the last whitespace separated piece (might span to next block)
parts = (remainder + block).rsplit(None, 1)
# Handle block with and without whitespace identically; no whitespace means
# probably handling EOF, just process what we've got and set remainder empty
toprocess, remainder = (parts + [''])[:2]
c.update(toprocess.split())
c.update(remainder.split()) # Add whatever was left over
这应该限制的最大存储器使用是相称的独特n元语法的数量,而不是在总线,非唯一n元语法的数目。
如果你有相对较少的独特的n-gram,那么这就足够了。如果你有很多独特的n-gram的虽然字符串化的Counter
可能耗费大量的内存太(虽然它本身会使用更加的Counter
,在str
也只是压垮骆驼的最后一根稻草)。一个简单的方法来打印计数每行一个是:
from itertools import starmap
with open('NGramCountOutput.txt', 'w') as outgrams:
# On Python 2, use .iteritems() instead of .items() to avoid large temp list
# If a temp list is okay, and you want sorted output by count,
# use .most_common() over .items()
outgrams.writelines(starmap('{} {}\n'.format, c.items()))
甚至 - '''为K,V在c.items():outgrams.write( “{}:{}” 的格式(K ,v))''' – wwii
考虑到在任何字符串化之前ngram是唯一的,除非_most_ ngrams是唯一的,'str'的内存开销不会那么高(并且它会比较在所有情况下都是“计数器”本身)。这是一个可能的问题/解决方案,但不是最有可能的问题/解决方案(只有在您已经非常接近系统内存限制的情况下才会发生,并且独特的ngram非常常见)。 – ShadowRanger
@wwii:或者当我们要进行荒谬的优化时,我的答案中的版本,“从itertools导入starmap”,“outmap.writelines(starmap('{}:{} \ n'.format,c.items ))'',它把所有的工作推到C层上运行得更快(我添加了一个新行,因为缺少一个会使计数运行到下面的ngrams中)。 – ShadowRanger