Введение

Крайне важный кейс для бизнеса — автоматизация бизнес процессов, где раньше можно было только использовать, например, оператора или клиентского менеджера, а сейчас им на помощь и замену чат-боты, голосовые ассистенты и вот и настало время, когда без машинного обучения и NLP уже никуда. Предлагаю рассмотреть NER сервисы и если обратиться к wikipedia:

Named-entity recognition (NER) (also known as (named) entity identification, entity chunking, and entity extraction) is a subtask of information extraction that seeks to locate and classify named entities mentioned in unstructured text into pre-defined categories such as person names, organizations, locations, medical codes, time expressions, quantities, monetary values, percentages, etc.

Что есть Named Entity Recognition или NER: логика и принцип работы

Т. е. Named Entity Recognition (NER) — это задача в области обработки естественного языка (NLP), направленная на выделение и классификацию именованных сущностей в тексте, таких как имена людей, названия организаций, даты, местоположения, суммы денег и другие типы специфических объектов. NER является важным компонентом многих NLP-приложений, таких как извлечение информации, анализ тональности, вопросно-ответные системы и многие другие, как раз наше направление чат-боты, голосовые ассистенты, смс, телефонные разговоры.

Основные подходы:

  1. Подход на основе правил (Rule-Based Approach). В этом подходе создаются наборы правил, которые определяют, какие последовательности слов в тексте могут быть именованными сущностями. Эти правила могут основываться на регулярных выражениях, шаблонах или лингвистических признаках. Примеры библиотек: spaCy (с поддержкой настраиваемых правил), NLTK.

  2. Подход на основе машинного обучения (Machine Learning-Based Approach). В этом подходе используются алгоритмы машинного обучения, такие как CRF (Conditional Random Fields), LSTM (Long Short-Term Memory) и BERT (Bidirectional Encoder Representations from Transformers), чтобы обучить модель распознавать именованные сущности. Модель обучается на размеченных данных, где сущности помечены в тексте. Примеры библиотек: spaCy (с обучаемыми моделями), Stanford NER, Flair.

  3. Совмещенный подход (Hybrid Approach). Этот подход объединяет правила и машинное обучение для улучшения точности NER. Можно сначала применить правила для выделения сущностей, а затем пропустить текст через модель машинного обучения для уточнения результатов.

А теперь немного о логике работы NER:

  1. Токенизация текста, т. е. текст разбивается на отдельные слова или токены;

  2. Выделение признаков — каждому токену назначаются признаки, которые описывают его окружение и контекст, такие как предыдущие и следующие слова, части речи и другие лингвистические характеристики;

  3. Применение модели — модель анализирует признаки каждого токена и определяет, является ли он именованной сущностью или нет;

  4. Объединение результатов — результаты анализа токенов объединяются, чтобы сформировать именованные сущности, и им назначаются соответствующие метки классов, такие как «PER« (для персон) или »ORG» (для организаций) ;

  5. Постобработка — дополнительная обработка для уточнения результатов или исправления ошибок;

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

О моей команде

Моя команда разрабатывает сложные решения и сервисы в BigData для бизнеса с профильным направлением графового анализа и геоанализа данных, также мы предлагаем и ML сервисы (Machine learning): один из которых для разметки аудио, текста и изображений (назовем его «Маркер»), а другие за NER-направление. Хотя совсем недавно я переключился на другой проект, но об этом в следующих статьях. (Мой Tg - @Vladimir_Lov)

Примеры NER сервисов

Наверное ты спросишь, а есть ли разница между обработкой сообщений чат-ботов, смс или телефонных разговоров? Да, но она крайне небольшая, если чат бот и смс — текстовая информация, то телефонный разговор — аудио, которое требуется перекодировать в текст, т. е. сделать расшифровку, а потом уже натравить на текст NER сервисы. Данный вид сервисов важен, так как позволяет автоматизировать часть процессов колл-центров и клиентских менеджеров, а также помочь с проверкой того что услышал, чтобы потом не возникало разногласий. Итого, NER сервисы это не просто применение готовых библиотек, а кастомизированый сервис, который содержит дополнительную логику под определеную бизнес задачу и помогают автоматически извлекать не только сущности, такие как имена клиентов, но и номера счетов, условия предложений, суммы перевода и т. п.

Практика

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

Возьмём фразу и сделаем набор кода, который нам поможет проанализировать и получить нужные нам сущности и параметры:

"Добрый день, я, Сидоров Иван Иванович. Прошу перевести сто тысяч рублей Якову Петру Игнатьевичу"

Как обработать данную фразу?

Сценарий:

  1. Собираем массив ФИО, где ФИО совпадающее с ФИО счета — платильщик, а второй элемент ФИО — получателя;

  2. Определяем тип запроса: перевести, оплатить, пополнить баланс и т. п;

  3. Находим сумма и её валюту, которую нужно перевести между счетами.

Код для извлечения ФИО

import spacy

def extract_names(text):
    nlp = spacy.load("ru_core_news_sm")
    doc = nlp(text)
    names = []
    for ent in doc.ents:
        if ent.label_ == "PER":
            names.append(ent.text)

    return names

def lemmatize_text(text):
    nlp = spacy.load("ru_core_news_sm")
    doc = nlp(text)
    lemmatized_text = " ".join([token.lemma_ for token in doc])
    return lemmatized_text

text = "Добрый день, я, Сидоров Иван Иванович. Прошу перевести сто тысяч рублей Якову Петру Игнатьевичу."
found_names = extract_names(text)

for i in range(0, len(found_names), 2):
    two_elements = found_names[i:i+2]
    result = ' '.join(two_elements)
    print("Найденное ФИО:", lemmatize_text(result))

Попробуем немного описать логику кода приведенного выше:

  • Импортирует библиотеку spacy, которая используется для обработки текста и с помощью предварительно обученной модели spacy для русского языка (ru_core_news_sm).

  • Определяем функцию extract_names(text), которая принимает текст в качестве входного аргумента. Функция выполняет следующие действия: загружает модель ru_core_news_sm, обрабатывает текст с созданием объект Doc, после чего, создает пустой список names для хранения найденных ФИО, проходим по сущностям (ent) в тексте и, если сущность имеет метку «PER» (персона), добавляет её в список names и возвращаем список names, содержащий найденные ФИО.

  • Определяет функцию lemmatize_text(text), которая принимает текст в качестве входного аргумента. Функция выполняет следующие действия: загружает модель для русского языка (аналогично прошлой функции), обрабатывает текст с помощью этой модели, создавая объект Doc, лемматизирует токены и объединяет в строку, разделенную пробелами, далее возвращает лемматизированный текст.

  • Извлекаем ФИО из исходного текста с помощью функции extract_names(text) и сохраняет результат в переменную found_names.

  • Использует цикл for, чтобы пройти по списку found_names и выводить ФИО по два элемента на каждой итерации. Каждая пара ФИО сначала конкатенируется с помощью пробела, затем проходит через функцию lemmatize_text для лемматизации, и наконец выводится на экран.

Таким образом, этот код выполняет извлечение ФИО из текста, лемматизацию ФИО и вывод лемматизированных ФИО по два на каждой итерации.

С ФИО тут просто, так как мы объявляем массив и потом сопоставляем, а вот с фразами типа: «перевести«, "отправь", »скинь» — немного сложнее, нужно в любом случае держать какой то объём допустимых слов-команд. В данном случае я не говорю по крайне ресурсоёмкие современные нейросети на подобии chat gpt, которые способны анализировать текст и ей подобные, будем пользоваться простыми и прозрачными библиотеками, которые не забанит ИБ (знающие поймут).

Код для выявления типа запроса клиента

from pymystem3 import Mystem

def find_word_in_text(text, word):
    mystem = Mystem()
    lemmatized_text = mystem.lemmatize(text.lower())
    
    if word in lemmatized_text:
        return True
    else:
        return False

phrase = "Добрый день, я, Сидоров Иван Иванович. Прошу перевести 100 тысяч рублей Якову Петру Игнатьевичу"
word = "перевести"

is_word_present = find_word_in_text(phrase, word)
print(is_word_present)

В этом примере мы используем библиотеку pymystem3 для лемматизации слов. Функция find_word_in_text принимает текст и слово, которое нужно найти, и возвращает True, если слово присутствует в тексте, и False, если нет. А теперь ещё раз, что мы сделали в блоке выше: приводим текст к нижнему регистру для удобства обработки, затем мы используем Mystem для лемматизации текста. После этого мы проверяем, присутствует ли исходное слово в лемматизированном тексте. Если да, функция возвращает, то как и написано выше — True.

Ну что, в принципе мы прошлись целиком по фразе и выявили всё что нам потребовалось… А нет, забыли про главное — деньги! Сколько перевести то?

Код для преобразования чисел в в виде цифр

#https://github.com/Oknolaz/Russian_w2n

from ru_word2number import w2n
text_russian = "Добрый день, я, Сидоров Иван Иванович. Прошу перевести сто тысяч рублей Якову Петру Игнатьевичу"
number_russian = w2n.word_to_num(text_russian)
print(f"Русский текст: {text_russian} -> Число: {number_russian}")

Код выше, использует библиотеку ru_word2number, которая предоставляет функциональность для преобразования чисел, записанных словами на русском языке, в числовой формат. Давай разберем логику работы этого кода:

  • Импорт библиотеки ru_word2number:pythonCopy codefrom ru_word2number import w2n Этой строкой кода мы импортируем функцию word_to_num из библиотеки ru_word2number, которая позволяет преобразовать текст, содержащий числа, записанные словами на русском языке, в числовой формат.

  • Задаем переменную — codetext_russian — с уже знакомым текстом. Здесь задается текст, в котором содержатся числа, записанные словами на русском языке. Этот текст будет подвергнут обработке, и числа будут преобразованы в числовой формат.

  • Преобразование текста происходит с помощью функции word_to_num из библиотеки ru_word2number. Результат преобразования сохраняется в переменной number_russian.

Таким образом, мы обработали текст с числами, записанными словами на русском языке и преобразовали в числовой формат.

Код для поиска валюты платежа

import re
import pymorphy2

text = "Добрый день, я, Сидоров Иван Иванович. Прошу перевести сто тысяч рублей Якову Петру Игнатьевичу"
morph = pymorphy2.MorphAnalyzer()
currency_pattern = r'\b(?:доллар(?:ов|)|евро|рубл(?:ь|я|ей))\b'
currencies_found = re.findall(currency_pattern, text, flags=re.IGNORECASE)
lemmatized_currencies = [morph.parse(word)[0].normal_form for word in currencies_found]

print("Найденные наименования валют:", currencies_found)
print("Лемматизированные формы:", lemmatized_currencies)

Данный код выполняет поиск наименований валют на русском языке (у каждой библиотеки, лемматизатора или модели есть ограничение по языкам) в заданном тексте и лемматизирует их с использованием библиотеки pymorphy2. Логика кода следующая:

  • Задается текст, в котором мы хотитим найти наименования валют.

  • Инициализируется лемматизатор с помощью pymorphy2.MorphAnalyzer().

  • Создается регулярное выражение currency_pattern, которое ищет наименования валют. Это регулярное выражение ищет следующие слова: «доллар«, "долларов", "евро", "рубль", "рубля", »рублей», игнорируя регистр (флаг re.ignorecase). В данной реализации ограничение — 3 валюты.

  • С использованием re. findall, производится поиск всех совпадений с регулярным выражением currency_pattern в заданном тексте. Результат поиска сохраняется в переменной currencies_found.

  • Далее, для каждого найденного наименования валюты из списка currencies_found, выполняется лемматизация с использованием morph. parse(word) [0]. normal_form. Это преобразует слово в его нормальную (лемматизированную) форму с учетом разных склонений и форм на русском языке. Лемматизированные формы сохраняются в переменной lemmatized_currencies.

  • Найденные наименования валют и их лемматизированные формы выводятся на экран.

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

Резюме

Итого мы вычленили ФИО отправителя и получателя, сумму и валюту, а также ключевое слово для определения сценария действий. Код написан на основе простых функций без учёта оптимальности. Написать подобный код не так сложно, а вот польза от этого кода колоссальная, так как помогает автоматизировать процесс и не заставлять клиентов ждать.

Приложение, если будет интересно

А теперь пример прямо с сайта библиотеки deeppavlov

Всем пока и до новых встреч!
P. S. надеюсь количество опечаток было минимальным

Комментарии (0)