Вы должны изменить 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
независимо от их отношения. Код, который я написал выше, только сохраняет слова, где собственное соотношение слова было достаточно высоким.
EDIT: Это ответ на вопрос об генераторных выражениях, которые должны быть заключены в скобки.
Всякий раз, когда я получаю это сообщение об ошибке, я обычно разделяю выражение генератора сам по себе и назначаю его переменной. Например:
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 на своей собственной линии.
EDIT: @Peter Wood указал, что в документации предлагается повторное использование SequenceMatcher
для скорости. У меня нет времени проверять это, но я думаю, что это правильный способ сделать это.
К счастью, код стал проще! Всегда хороший знак.
EDIT: Я только что проверил код. Этот код работает для меня; посмотрите, работает ли это для вас.
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)
Я не» t согласен. Он более или менее ищет альтернативные подходы – keyser
Это проблема структур данных. – wim
Вы имели в виду 'm = SequenceMatcher (None, y.lower(), x)' – wim