def read_trigrams(fobj):
unique = {}
def make_unique(w):
w = w.strip("\"'`!?,.():-;{}").lower()
return unique.setdefault(w, w)
fobj.seek(0, 2)
total_size = fobj.tell()
fobj.seek(0, 0)
read = 0
prev_words = []
for idx, line in enumerate(fobj):
read += len(line)
words = prev_words
words.extend(filter(None, (make_unique(w) for w in line.split())))
if len(words) > 3:
for i in range(len(words) - 3):
yield tuple(words[i:i+3])
prev_words = words[-2:]
import sys
import pickle
def merger(inputs):
unpicklers = [pickle.Unpickler(open(f, 'rb')) for f in inputs]
DONE = (object(), )
NEXT = (object(), )
peek = [NEXT] * len(unpicklers)
while True:
for idx in range(len(unpicklers)):
if peek[idx] is NEXT:
try:
peek[idx] = unpicklers[idx].load()
except EOFError:
peek[idx] = DONE
if all(v is DONE for v in peek):
return
min_key = min(v[0] for v in peek if v is not DONE)
yield min_key, sum(v[1] for v in peek if v[0] == min_key)
peek = [NEXT if (v[0] == min_key) else v for v in peek]
for trigram, count in merger(sys.argv[1:]):
print(trigram, count)
from collections import defaultdict
chars = set('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
def cleanWord(s):
return ''.join(c for c in s if c in chars)
f = open('moby dick.txt') #downloaded from Project Gutenberg: http://www.gutenberg.org/ebooks/2701 Thanks!
words = f.read().split()
f.close()
words = [cleanWord(w.upper()) for w in words]
words = [w for w in words if len(w) > 1 and not(w in set('AIOY'))]
repeatedWords = defaultdict(int)
for w in words:
repeatedWords[w] += 1
repeatedWords = set(w for w in repeatedWords if repeatedWords[w] > 1)
repeatedBigrams = defaultdict(int)
for i in range(len(words) - 1):
x,y = words[i:i+2]
if x in repeatedWords or y in repeatedWords:
repeatedBigrams[x + ' ' + y] +=1
repeatedBigrams = set(b for b in repeatedBigrams if repeatedBigrams[b] > 1)
repeatedTrigrams = defaultdict(int)
for i in range(len(words) - 2):
x,y,z = words[i:i+3]
if x + ' ' + y in repeatedBigrams and y + ' ' + z in repeatedBigrams:
repeatedTrigrams[x + ' ' + y + ' ' + z] +=1
repeatedTrigrams = {t:c for t,c in repeatedTrigrams.items() if c > 1}
arrayOfTrigrams.sort()
repeatedTrigrams = {}
for i,t in enumerate(arrayOfTrigrams):
if i > 0 and arrayOfTrigrams[i-1] == t:
if t in repeatedTrigrams:
repeatedTrigrams[t] += 1
else:
repeatedTrigrams[t] = 2
在构造repeatedTrigrams之后,您可以使用集合理解:
uniques = {t for t in arrayOfTrigrams if not t in repeatedTrigrams}
然后t in uniques将传递t的计数为1的信息,我怀疑这对于绝大多数的三元曲线都是正确的。在这一阶段,您拥有所有相关频率信息,并可以放弃trigrams列表,以释放一些已消耗的内存:
我的第一个建议是不要将
arrayOfTrigrams
完全保存在内存中,而是使用流式处理。你是从某个地方读的,所以你可以控制你读它的方式。Python的生成器在这里非常方便。假设你是从文件中读的:这里有两件事:
N
时间读取相同的字节序列S
确实占用了N*len(S)
个字节。通过使用字典,我们确保输入中每个单词都有一个唯一的副本。当然,这会消耗一些内存。在这个函数对你来说可能不同,这取决于你从哪里读到你的八卦。请记住,我在这里使用的标记器是非常基本的。在
这已经节省了一点内存,但不是太多。在
所以,让我们将中间结果存储在磁盘上:
^{pr2}$在这一步中,您可以调整
LIMIT
以不使用太多内存,也就是说,只要减少它,直到您不再使用MemoryError
。在现在,驱动器上有
N
个文件,其中有一个经过排序的三元组列表。在一个单独的程序中,您可以读入并汇总所有中间计数:如果你有4吉布的内存,你实际上可能不得不使用拆分功能。有了8吉布斯,你应该能够保持所有的内存。在
在进一步编辑包含的代码时如果您能够在内存中保存
arrayOfTrigrams
,请参阅底部的原始解决方案。但是,如果您还不能创建arrayOfTrigrams
(鉴于数据大小,我有点怀疑您是否已经做到了这一点),您仍然可以创建一个包含重复三元组的字典。重复的双元组总是包含重复的单词,重复的三元组包含重复的双元组。分阶段处理500 MB的数据。首先创建一组重复的单词。使用这个,创建一个重复的双元组字典。首先对包含一个重复单词的双元组进行原始频率计数,然后丢弃计数仅为1的任何双元组。然后对数据进行第三次处理,创建重复三元组字典。同样,对包含重复的二元曲线(应该是所有可能的三元曲线的一小部分)进行原始频率计数,然后从字典中丢弃最终计数为1的那些。这样你就可以建立字典,而不需要一次将所有的三元组保存在内存中。在概念证明:
这段代码显示10016个多次出现的三元组。相反,当我评估
^{pr2}$我得到了188285,所以在这个有点大的自然语言例子中,只有10016/188285=5.3%的可能的三元组是重复的。假设您的数据也有类似的比率,我估计用于重复三角函数的频率字典的大小大约为100MB。在
原液:
您的代码和问题表明您可以在内存中保存
arrayOfTrigrams
,但无法创建字典。一个潜在的解决方法是首先对这个数组进行排序,然后创建一个重复三元组的频率计数:在构造
repeatedTrigrams
之后,您可以使用集合理解:然后
t in uniques
将传递t
的计数为1的信息,我怀疑这对于绝大多数的三元曲线都是正确的。在这一阶段,您拥有所有相关频率信息,并可以放弃trigrams列表,以释放一些已消耗的内存:相关问题 更多 >
编程相关推荐