你应该把
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()
m, word = max((SequenceMatcher(None, y, word), word) for word in headwords, key=check_ratio)
percentage = max(percentage, m.ratio())
if m.ratio() > 0.86:
setence_list.append(word)
这可能看起来有些棘手,但这是在Python中执行此操作的最快方法。我们将调用内置的
max()
函数,在
headwords
中尝试所有单词并找到具有最高比率的
SequenceMatcher
结果。首先,我们构建一个“生成器表达式”,在其中对每个单词调用
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()
genexp = ((SequenceMatcher(None, y, word), word) for word in headwords)
m, word = max(genexp, key=check_ratio)
percentage = max(percentage, m.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 = [
"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)
if ratio > 0.86:
ratios[word] = ratio
print(best_ratio)
print(ratios)
headwordList
改为集合而不是列表,以获得更好的查找性能,用于那些in
检查。 - wimif y not in headwordList:
部分。 - alko