您应该将headwordList 更改为set。
测试word in headwordList 会很慢。它必须对headwordList 中的每个单词进行字符串比较,一次一个单词。这将花费与列表长度成正比的时间;如果将列表的长度加倍,则进行测试所需的时间将加倍(平均)。
使用set,执行in 测试总是需要相同的时间;它不依赖于set 中的元素数量。所以这将是一个巨大的加速。
现在,整个循环可以简化:
for x in headwordList:
m = SequenceMatcher(None, y.lower(), x)
if m.ratio() > percentage:
percentage = m.ratio()
word = x
if percentage > 0.86:
sentenceList[count] = word
所有这一切都是从headwordList中找到比率最高的单词,并保留它(但只有在比率超过0.86时才保留它)。这是一种更快的方法。我要将名称 headwordList 更改为 headwords,因为我希望您将其改为 set 而不是 list。
def check_ratio(m):
return m.ratio()
y = y.lower() # do the .lower() call one time
m, word = max((SequenceMatcher(None, y, word), word) for word in headwords, key=check_ratio)
percentage = max(percentage, m.ratio()) # remember best ratio
if m.ratio() > 0.86:
setence_list.append(word)
这可能看起来有点棘手,但它是 Python 中最快的方法。我们将调用内置的max() 函数来查找具有最高比率的SequenceMatcher 结果。首先,我们构建一个“生成器表达式”来尝试headwords 中的所有单词,并在每个单词上调用SequenceMatcher()。但是当我们完成后,我们也想知道这个词是什么。所以生成器表达式生成元组,其中元组中的第一个值是SequenceMatcher 结果,第二个值是单词。 max() 函数无法知道我们关心的是比率,所以我们必须告诉它;我们通过创建一个函数来测试我们关心的内容,然后将该函数作为key= 参数传递。现在max() 为我们找到了比率最高的值。 max() 使用生成器表达式生成的所有值并返回单个值,然后我们将其解压缩到变量 m 和 word 中。
在 Python 中,最好使用像 sentence_list 这样的变量名而不是 sentenceList。请参阅以下指南:http://www.python.org/dev/peps/pep-0008/
使用递增索引变量并分配到列表中的索引位置不是一个好习惯。而是从一个空列表开始,然后使用 .append() 方法函数来附加值。
另外,你最好建立一个单词字典和它们的比率。
请注意,您的原始代码似乎有一个错误:只要任何单词的百分比超过 0.86,所有单词都会保存在 sentenceList 中,无论它们的比例是多少。上面我写的代码,只保存单词自身比例足够高的单词。
编辑:这是为了回答关于生成器表达式需要加括号的问题。
每当我收到该错误消息时,我通常会自行拆分生成器表达式并将其分配给一个变量。像这样:
def check_ratio(m):
return m.ratio()
y = y.lower() # do the .lower() call one time
genexp = ((SequenceMatcher(None, y, word), word) for word in headwords)
m, word = max(genexp, key=check_ratio)
percentage = max(percentage, m.ratio()) # remember best ratio
if m.ratio() > 0.86:
setence_list.append(word)
这就是我的建议。但是,如果您不介意复杂的行看起来更忙,您可以简单地添加一对额外的括号,如错误消息所示,因此生成器表达式完全被括号括起来。像这样:
m, word = max(((SequenceMatcher(None, y, word), word) for word in headwords), key=check_ratio)
当您将表达式传递给函数时,Python 允许您省略围绕生成器表达式的显式括号,但前提是它是该函数的唯一参数。由于我们还传递了一个 key= 参数,因此我们需要一个完全带括号的生成器表达式。
但我认为,如果您将 genexp 拆分为单独的行,则更易于阅读。
编辑:@Peter Wood 指出文档建议重用 SequenceMatcher 以提高速度。我没有时间对此进行测试,但我认为这是正确的方法。
很高兴,代码变得更简单了!总是一个好兆头。
编辑:我刚刚测试了代码。这段代码对我有用;看看它是否适合你。
from difflib import SequenceMatcher
headwords = [
# This is a list of 650,000 words
# Dummy list:
"happy",
"new",
"year",
]
def words_from_file(filename):
with open(filename, "rt") as f:
for line in f:
for word in line.split():
yield word
def _match(matcher, s):
matcher.set_seq2(s)
return (matcher.ratio(), s)
ratios = {}
best_ratio = 0
matcher = SequenceMatcher()
for word in words_from_file("sentences.txt"):
matcher.set_seq1(word.lower())
if word not in headwords:
ratio, word = max(_match(matcher, word.lower()) for word in headwords)
best_ratio = max(best_ratio, ratio) # remember best ratio
if ratio > 0.86:
ratios[word] = ratio
print(best_ratio)
print(ratios)