Время прочтения: 7 мин.

Как работает алгоритм FlashText.

Модуль FlashText основан на собственном алгоритме FlashText. По сути, он основан на реализации Python алгоритма Ахо – Корасика.

Основная задача алгоритма — сократить время, затрачиваемое на поиск большого количества ключевых слов в тексте, за счет минимизации количества сканирований текста.

“Наивный” (простой) алгоритм состоит из сравнения каждого ключевого слова с каждым словом во всем тексте — подобно линейному поиску.

Такой подход крайне неэффективен, потому что для этого необходимо n раз сканировать весь текстовый документ, где n — количество ключевых слов. 

   Алгоритм FlashText выбирает другой подход, он сканирует текст только один раз.

Эффективность алгоритма FlashText заключается в том, что он сохраняет все ключевые слова вместе с соответствующими заменяющими словами в словаре.

Затем вместо того, чтобы сканировать текст один раз для каждого ключевого слова в словаре, он просматривает текст только один раз.

В этом одном просмотре текста слова сопоставляются с ключами словаря и, если они есть, заменяются значением ключа. 

 Установим FlashText.

Установить «FlashText» просто, используем pip install:

pip install flashtext 

Как использовать FlashText.

Давайте вначале взглянем на FlashText API и некоторые ключевые классы в нем.

Класс KeywordProcessor

Основным классом, с которым будем работать, занимается обработкой ключевых слов, это класс KeywordProcessor.

Импортируем его прямо из FlashText и инициализируем:

from flashtext import KeywordProcessor
keyword_processor = KeywordProcessor()

Предыдущая строка создает объект KeywordProcessor, который будет работать в режиме без учета регистра.

Режим без учета регистра будет соответствовать abc с ABC, а также с aBc, ABc и т. д.

Режим с учетом регистра будет соответствовать только aaa с точно такой же строкой, aaa.

В качестве альтернативного варианта можем создать экземпляр KeywordProcessor в режиме с учетом регистра:

keyword_processor= KeywordProcessor(case_sensitive=True)

Определение словаря ключевых слов

В модуле FlashText мы используем ключевые слова для определения их в тексте, которые хотим заменить.

 Объект KeywordProcessor содержит словарь, содержащий все определенные ключевые слова для определения их в тексте.

Есть два способа добавления ключевых слов в словарь: массово или по одному.

Во-первых, давайте посмотрим, как добавлять ключевые слова по одному:

keyword_processor.add_keyword(<keyword>, <replacementWord>)

<replacementWord> — необязательный аргумент. Если не указано иное, в словарь добавляется только <ключевое слово>, и нет возможности заменить его другим заменяющим словом.

Итак, если вы хотите использовать FlashText для замены слов в тексте, лучше использовать   аргумент <replacementWord>.

Если у нас несколько ключевых слов, добавление их по одному может занять мало времени.

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

keyword_dictionary = {
    'replacementWord_1': ['Лист', 'выключить', 'ключ', 'после', 'replacementWord_1'],
    'replacementWord_2': ['Лист', 'выключить', 'ключ', 'после, 'replacementWord_2'],
    ...
    'replacementWord_N': ['Лист', 'выключить', 'ключ', 'после, 'replacementWord_N']
}
keyword_processor.add_keywords_from_dict(keyword_dictionary )

Каждый ключ в словаре — это строковое ключевое слово. Каждое значение должно быть списком.

В качестве альтернативы можете указать ключевые слова с помощью списка:

keyword_processor.add_keywords_from_list(['Лист', 'выключить', 'ключ'])

Но при таком подходе — вы просто добавляете ключевые слова без заменяющих слов.

Или, если текстовый файл содержит пары ключ-значение, следующие за синтаксисом ключ => значение:

keyword1=>value1
keyword2=>value2

Мы можем импортировать их с помощью функции keywords_from_file ():

keyword_processor.add_keywords_from_file('key_list.txt')

Часто используемый подход, который обеспечивает максимальную гибкость и удобство чтения, — это использование словаря.

Это также наиболее естественное совпадение для алгоритма, учитывая тот факт, что в конечном итоге все это попадает в словарь.

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

Мы бы добавили эти ключевые слова и replace_words в keyword_dictionary:

keyword_dictionary = {
    "плохой": ["отвратительно", "нехорошо", "нежелательно"],
    "хорошо": ["чудесно", "великолепно", "прекрасно",]
}

И, наконец, добавьте keyword_dictionary к объекту keyword_processor:

keyword_processor.add_keywords_from_dict(keyword_dictionary)

Заменим ключевые слова заменяющими словами

После того, как мы загрузили ключевые слова и соответствующие им заменяющие слова в экземпляр KeywordProcessor, мы можем выполнить функцию replace_keywords (), которая сканирует предоставленный текст и выполняет замену:

new_text_1 = keywordProcessor.replace_keywords("Passed String")

Он анализирует предоставленный текст, заменяя все ключевые слова в нем соответствующими значениями и возвращает новую строку.

Обычно мы здесь не работаем со строковыми литералами, а скорее с документами. Нам нужно открыть документ, прочитать строки в нем и передать их в виде строки в функцию replace_keywords ().

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

Загрузим текстовый файл и выполним функцию replace_keywords () над содержимым:

with open('data_1.txt', 'r+') as file:
    content = file.read()
    new_content_1 = keyword_processor.replace_keywords(content)
    file.seek(0)
    file.truncate()
    file.write(new_content_1)

Если мы загрузим текстовый файл, такой как text_1.txt: Завтрак был потрясающий! Мне очень понравилась яичница, ты отличный повар.

Со следующими ключевыми словами и заменяющими словами:

from flashtext import KeywordProcessor
keyword_processor = KeywordProcessor()

keyword_dictionary = {
    "отличный": ["потрясающий", " понравилась"],
    " яичница ": ["омлет"]
}

keyword_processor.add_keywords_from_dict(keyword_dictionary)

with open('data_1.txt', 'r+') as file:
    content_1 = file.read()
    new_content_1 = keyword_processor.replace_keywords(content_1)
    file.seek(0)
    file.truncate()
    file.write(new_content_1)

Это приведет к изменению файла text_1.txt: Завтрак был отличный! И очень отличный омлет, ты отличный повар.

Полезные функции модуля FlashText

Давайте создадим фиктивные ключевые слова keyword_processor и keyword_dictionary, чтобы проиллюстрировать некоторые другие полезные функции модуля FlashText:

keywordProcessor = KeywordProcessor()
keywordDictionary = {
    "плохо": ["ужасный", "невозможный", "отвратительный"],
    "хорошо": ["отлично", "превосходно", "великолепно"]
}
keywordProcessor.add_keywords_from_dict(keywordDictionary)

Чтобы получить список всех ключевых слов в экземпляре KeywordProcessor, мы используем функцию get_all_keywords ():

print(keywordProcessor.get_all_keywords())

Что приводит к:

{'ужасный': 'плохо', 'невозможный': 'плохо', 'отвратительный': 'плохо', 'отлично': 'хорошо', 'превосходно': 'хорошо', 'великолепно': 'хорошо'}

Чтобы проверить, присутствует ли ключевое слово в KeywordProcessor, мы можем использовать оператор in:

'плохо' in keywordProcessor
'красный' in keywordProcessor
'ужасный' in keywordProcessor

И чтобы получить доступ к replace_word на основе определенного ключевого слова:

keywordProcessor['отлично']
keywordProcessor['превосходно']
keywordProcessor['хороший']

И, наконец, чтобы удалить ключевые слова из KeywordProcessor, мы используем функцию remove_keyword ():

keyword_processor.remove_keyword('отлично')

В качестве альтернативы, можем указать список или словарь пар ключевое слово-значение, которые хотим удалить, и использовать их для удаления указанных элементов:

keywordProcessor.remove_keywords_from_dict({"плохо": ["ужасный", "отвратительный"]})
keywordProcessor.remove_keywords_from_list(["прекрасно", "превосходно"])

FlashText против регулярных выражений

FlashText создавался как альтернатива регулярным выражениям, и поэтому было бы полезно сравнить их оба.

Фактически, он был создан как ответ на вопрос о StackOverflow.

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

Тесты показали, что FlashText требует меньше времени, чем RegEx, для поиска и замены ключевых слов, когда количество ключевых слов превышает 500.

Но когда дело доходит до сопоставления специальных символов, FlashText не имеет шансов превзойти регулярные выражения. Кроме того, FlashText даже не поддерживает такого рода сопоставление — он может сопоставлять только простые ключевые слова без каких-либо специальных символов.

Сопоставление специальных символов описывает ситуации, когда некоторые символы в слове имеют особое значение и могут соответствовать нескольким различным символам. Например, символ \ d описывает цифры от 0 до 9, что означает, что ключевое слово number \ d будет соответствовать словам number0, number1, number2 и т. д.

Важно: FlashText не предназначен для сопоставления специальных символов, поэтому он может сопоставлять только одинаковые строковые литералы. Слово number1 можно сопоставить только с ключевым словом number1, и невозможно использовать одно ключевое слово для сопоставления (сравнения) с несколькими разными словами.

Итак,  FlashText — очень простой, но производительный по скорости инструмент. Он довольно легкий, простой в освоении и очень эффективен по времени, независимо от количества заменяемых ключевых слов. Как и в случае с любым другим инструментом, важно знать, какой сценарий его использования является наилучшим. Если у вас есть более 500 ключевых слов, которые нужно заменить, и эти ключевые слова простые, без каких-либо специальных символов, то вместо регулярных выражений используем FlashText. И обратный вариант, если у вас меньше 500 ключевых слов и есть специальные символы, вам, следует отказаться от FlashText и использовать регулярные выражения, учитывая их гибкость и синтаксис.