我有一个巨大的文本文件的字符串缓冲区。我必须在字符串缓冲区中搜索给定的单词/短语。什么是有效的方法呢?
我尝试使用re模块匹配。但由于我有一个巨大的文本语料库,我必须搜索。这需要花费大量时间。
给出单词和短语词典。
我遍历每个文件,将其读入字符串,搜索字典中的所有单词和短语,并在找到密钥时增加字典中的计数。
我们认为的一个小优化是将短语/单词的字典排序为最大字数。然后比较字符串缓冲区中的每个单词起始位置并比较单词列表。如果找到一个短语,我们不会搜索其他短语(因为它匹配最长的短语,这就是我们想要的)
有人可以建议如何在字符串缓冲区中逐字逐句。 (逐字迭代字符串缓冲区)?
此外,还有其他优化可以做到吗?
data = str(file_content)
for j in dictionary_entity.keys():
cnt = data.count(j+" ")
if cnt != -1:
dictionary_entity[j] = dictionary_entity[j] + cnt
f.close()
答案 0 :(得分:7)
通过文件的内容(在我的案例中来自Project Gutenberg的绿野仙踪)逐字逐句地进行迭代,有三种不同的方式:
from __future__ import with_statement
import time
import re
from cStringIO import StringIO
def word_iter_std(filename):
start = time.time()
with open(filename) as f:
for line in f:
for word in line.split():
yield word
print 'iter_std took %0.6f seconds' % (time.time() - start)
def word_iter_re(filename):
start = time.time()
with open(filename) as f:
txt = f.read()
for word in re.finditer('\w+', txt):
yield word
print 'iter_re took %0.6f seconds' % (time.time() - start)
def word_iter_stringio(filename):
start = time.time()
with open(filename) as f:
io = StringIO(f.read())
for line in io:
for word in line.split():
yield word
print 'iter_io took %0.6f seconds' % (time.time() - start)
woo = '/tmp/woo.txt'
for word in word_iter_std(woo): pass
for word in word_iter_re(woo): pass
for word in word_iter_stringio(woo): pass
导致:
% python /tmp/junk.py
iter_std took 0.016321 seconds
iter_re took 0.028345 seconds
iter_io took 0.016230 seconds
答案 1 :(得分:1)
这听起来像trie真正有用的问题。您可能应该使用某种类似压缩的trie,如Patricia/radix trie。只要你能够在trie中找到你想要的整个单词/短语词典,这将大大减少时间复杂度。如何工作是你取一个单词的开头并下降trie直到找到最长的匹配并递增该节点中的计数器。这可能意味着如果部分匹配没有消失,你必须提升trie。然后你将进入下一个单词的开头并再次进行。 trie的优点在于,您通过trie搜索整个字典(每个查找应该占用O(m),其中m是字典中单词/短语的平均长度)。
如果你不能将整个字典整合成一个trie,那么你可以将字典分成几次尝试(一个用于所有以al开头的单词/短语,一个用于mz)并在整个过程中进行扫描每个特里的语料库。
答案 2 :(得分:0)
如果re
模块无法快速完成,那么您将很难以更快的速度完成任务。无论哪种方式,您都需要读取整个文件。您可以考虑修复正则表达式(可以提供一个吗?)。也许还有一些关于你想要完成的事情的背景知识。
答案 3 :(得分:0)
你可以尝试反过来...而不是处理文本语料库2,000,000次(每个单词一次),只处理一次。对于语料库中的每个单词,递增哈希表或类似词以存储该词的计数。伪代码中的一个简单示例:
word_counts = new hash<string,int>
for each word in corpus:
if exists(word_counts[word]):
word_counts[word]++
else:
word_counts[word] = 1
您可以通过使用完整的单词列表提前初始化word_counts来加快速度,这不需要if语句......不确定。
答案 4 :(得分:0)
正如xyld所说,我不认为你可以超越re模块的速度,尽管如果你发布你的正则表达式以及可能的代码也会有所帮助。我可以添加的是在优化之前尝试分析。当您看到大部分处理过程时,您可能会感到非常惊讶。我使用hotshot来分析我的代码,我很满意。你可以在这里找到对python概要分析的一个很好的介绍http://onlamp.com/pub/a/python/2005/12/15/profiling.html。
答案 5 :(得分:0)
如果使用re
的性能不够,您可能正在使用findall()
,或者手动逐个查找匹配项。使用迭代器可能会更快:
>>> for i in re.finditer(r'\w+', 'Hello, this is a sentence.'):
... print i.group(0)
...
Hello
this
is
a
sentence
答案 6 :(得分:0)
#!/usr/bin/env python
import re
s = ''
for i in xrange(0, 100000):
s = s + 'Hello, this is a sentence. '
if i == 50000:
s = s + " my phrase "
s = s + 'AARRGH'
print len(s)
itr = re.compile(r'(my phrase)|(\w+)').finditer(s)
for w in itr:
if w.group(0) == 'AARRGH':
print 'Found AARRGH'
elif w.group(0) == "my phrase":
print 'Found "my phrase"'
运行这个,我们得到
$ time python itrword.py
2700017
Found "my phrase"
Found AARRGH
real 0m0.616s
user 0m0.573s
sys 0m0.033s
但是,明确添加到正则表达式中的每个“短语”都会对性能产生影响 - 通过粗略测量,上述速度比使用“\ w +”慢50%。
答案 7 :(得分:0)
您是否考虑过查看Natural Language Toolkit。它包含许多用于处理文本语料库的好函数,还有一个很酷的FreqDist类,它具有类似dict(有键)和类似列表(slice)的行为。