Я пытаюсь сравнить два предложения и посмотреть, содержат ли они одинаковый набор слов.
Например: сравнение «сегодня хороший день» и «сегодня хороший день» должно вернуть true
Я использую функцию Счетчик из модуля коллекций прямо сейчас

from collections import Counter


vocab = {}
for line in file_ob:
    flag = 0
    for sentence in vocab:
        if Counter(sentence.split(" ")) == Counter(line.split(" ")):
            vocab[sentence]+=1
            flag = 1
            break
        if flag==0:
            vocab[line]=1

Кажется, что он отлично работает на несколько строк, но мой текстовый файл имеет более 1000, и он никогда не завершает выполнение. Есть ли другой способ, более эффективный, который помог бы мне вычислить результат для всего файла?

РЕДАКТИРОВАТЬ:

Мне просто нужна замена для метода Counter, чтобы что-то заменить. И никаких изменений в реализации.

7
TheLastCoder 25 Июн 2019 в 23:22

3 ответа

В своем коде вы можете извлечь конструкцию Counter вне внутреннего цикла, вместо того, чтобы пересчитывать каждую для каждой пары - это должно улучшить алгоритм на коэффициент, пропорциональный среднему числу токенов на строку.

from collections import Counter
vocab = {a dictionary of around 1000 sentences as keys}

vocab_counter = {k: Counter(k.split(" ")) for k in vocab.keys() }

for line in file_obj:
    line_counter = Counter(line.split(" "))
    for sentence in vocab:
        if vocab_counter[sentence] == line_counter:
            vocab[sentence]+=1

Дальнейшие улучшения могут быть достигнуты за счет использования счетчиков в качестве индексов для словаря, что позволит вам заменить линейный поиск подходящих предложений поиском. Пакет frozendict, вероятно, будет полезен, чтобы вы могли использовать словарь в качестве ключа к другому словарю.

2
Neal Fultz 25 Июн 2019 в 20:34

Чтобы учесть повторяющиеся / множественные слова, ваше сравнение на равенство может быть:

def hash_sentence(s):                                                                                                                                                                                                                                         
    return hash(''.join(sorted(s.split())))                                                                                                                                                                                                                   

a = 'today is a good day'                                                                                                                                                                                                                                     
b = 'is today a good day'                                                                                                                                                                                                                                     
c = 'today is a good day is a good day'                                                                                                                                                                                                                       

hash_sentence(a) == hash_sentence(b)  # True
hash_sentence(a) == hash_sentence(c)  # False

Также обратите внимание, что в вашей реализации каждое предложение подсчитывается n раз (for sentence in vocab:).

2
Markus Rother 25 Июн 2019 в 20:50

Попробуйте что-то вроде

set(sentence.split(" ")) == set(line.split(" "))

Сравнение объектов set быстрее, чем сравнение счетчика . Объекты set и counter в основном являются наборами, однако, когда вы используете объект counter для сравнения, он должен сравнивать и ключи, и значения, тогда как набор должен сравнивать только ключи.
Спасибо Эрику и Бармару за ваш вклад.

Ваш полный код будет выглядеть

from collections import Counter
vocab = {a dictionary of around 1000 sentences as keys}
for line in file_ob:
    for sentence in vocab:
        if set(sentence.split(" ")) == set(line.split(" ")):
            vocab[sentence]+=1

3
DataCruncher 25 Июн 2019 в 21:46