问题定义:给定长度为n
个字符的文本和长度为t
的术语列表(可能是正则表达式),找到并计算文本中所有出现的术语。< / p>
这是一个天真的实现:
class WordFrequency(TextAnalysis):
"""Determines the frequency of words from a vocabulary in a given text"""
def __init__(self, vocabulary, text):
"""
:param vocabulary: contains the words (e.g. list)
:param text: the analysed text
"""
self.text = text
self.vocabulary = vocabulary
self.matches = {}
def run(self):
"""
:return: self for method chaining
"""
ltext = self.text.lower()
self.freq = {} # word -> absolute frequency
for word in self.vocabulary:
matches = re.findall(r'\b' + word + r'\b', ltext)
self.matches[word] = [match for match in matches] #.lstrip() for match in matches]
self.freq[word] = len(matches)
return self
现在,对于长度为ca的文本,这需要大约6秒钟。 35000个字符和一个ca. 5000条,这太慢了。似乎时间复杂度为O(t * n)
,因为对于每个t
术语,文本必须扫描一次。这里有明显的性能错误吗?什么是可能的优化和/或更好的算法?
答案 0 :(得分:1)
这可以在n O(t * log(n))中工作。我目前有两个在生产中运行的实现
实施#1:
完成纯Python。我从(较小的)模式文件构造了一个搜索树,其中树的每个节点都是一个字母,链接到可能的下一个字母的哈希。例如,你有三种模式:猫,狗和闪避。以下树在O(n)中自动构造:
{
'c': {'a': {'t': 'cat'}},
'd': {'d': {'g': {'e': 'dodge'}},
'o': {'g': 'dog'}}
}
您现在可以扫描文本并在O(log(n))中查找此查找树中的每个单词(或每个字符)。
虽然有可能,但我不支持此解决方案的正则表达式。缺点是Python没有很好的性能,而哈希树在消耗多少内存方面效率低下。我打算使用Pypy,用Perl或C重写它并进行多处理。
实施#2:
一个名为grep
的知名工具已经完成了上述所有工作。它支持正则表达式,可以接受模式文件。由于某种原因,它不喜欢大型模式文件,并且随着模式文件的增加,其性能呈指数级降低。这可能是因为我大量使用正则表达式。我最终在多个切片中分割模式文件,并在并行进程中将它们提供给grep。对于我的应用程序,grep的速度提高了10倍。注意:将环境变量$ LANG设置为'',因为grep受到严重的本地化缓慢的阻碍。
结论:
在C中构建目标引擎将是理想的选择,但通过使用可用且广泛使用的GPL工具可以为您节省几个月的生命。