Введение
Крайне важный кейс для бизнеса — автоматизация бизнес процессов, где раньше можно было только использовать, например, оператора или клиентского менеджера, а сейчас им на помощь и замену чат-боты, голосовые ассистенты и вот и настало время, когда без машинного обучения и 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-приложений, таких как извлечение информации, анализ тональности, вопросно-ответные системы и многие другие, как раз наше направление чат-боты, голосовые ассистенты, смс, телефонные разговоры.
Основные подходы:
Подход на основе правил (Rule-Based Approach). В этом подходе создаются наборы правил, которые определяют, какие последовательности слов в тексте могут быть именованными сущностями. Эти правила могут основываться на регулярных выражениях, шаблонах или лингвистических признаках. Примеры библиотек: spaCy (с поддержкой настраиваемых правил), NLTK.
Подход на основе машинного обучения (Machine Learning-Based Approach). В этом подходе используются алгоритмы машинного обучения, такие как CRF (Conditional Random Fields), LSTM (Long Short-Term Memory) и BERT (Bidirectional Encoder Representations from Transformers), чтобы обучить модель распознавать именованные сущности. Модель обучается на размеченных данных, где сущности помечены в тексте. Примеры библиотек: spaCy (с обучаемыми моделями), Stanford NER, Flair.
Совмещенный подход (Hybrid Approach). Этот подход объединяет правила и машинное обучение для улучшения точности NER. Можно сначала применить правила для выделения сущностей, а затем пропустить текст через модель машинного обучения для уточнения результатов.
А теперь немного о логике работы NER:
Токенизация текста, т. е. текст разбивается на отдельные слова или токены;
Выделение признаков — каждому токену назначаются признаки, которые описывают его окружение и контекст, такие как предыдущие и следующие слова, части речи и другие лингвистические характеристики;
Применение модели — модель анализирует признаки каждого токена и определяет, является ли он именованной сущностью или нет;
Объединение результатов — результаты анализа токенов объединяются, чтобы сформировать именованные сущности, и им назначаются соответствующие метки классов, такие как «PER« (для персон) или »ORG» (для организаций) ;
Постобработка — дополнительная обработка для уточнения результатов или исправления ошибок;
Библиотеки для NER предоставляют готовые решения для выделения именованных сущностей и могут быть адаптированы под конкретные задачи и типы данных, как например кейсы, описанные в начале статьи. Выбор конкретной библиотеки зависит от требований проекта, языка и доступных данных для обучения, конечно если используется машинное обучение.
О моей команде
Моя команда разрабатывает сложные решения и сервисы в BigData для бизнеса с профильным направлением графового анализа и геоанализа данных, также мы предлагаем и ML сервисы (Machine learning): один из которых для разметки аудио, текста и изображений (назовем его «Маркер»), а другие за NER-направление. Хотя совсем недавно я переключился на другой проект, но об этом в следующих статьях. (Мой Tg - @Vladimir_Lov)
Примеры NER сервисов
Наверное ты спросишь, а есть ли разница между обработкой сообщений чат-ботов, смс или телефонных разговоров? Да, но она крайне небольшая, если чат бот и смс — текстовая информация, то телефонный разговор — аудио, которое требуется перекодировать в текст, т. е. сделать расшифровку, а потом уже натравить на текст NER сервисы. Данный вид сервисов важен, так как позволяет автоматизировать часть процессов колл-центров и клиентских менеджеров, а также помочь с проверкой того что услышал, чтобы потом не возникало разногласий. Итого, NER сервисы это не просто применение готовых библиотек, а кастомизированый сервис, который содержит дополнительную логику под определеную бизнес задачу и помогают автоматически извлекать не только сущности, такие как имена клиентов, но и номера счетов, условия предложений, суммы перевода и т. п.
Практика
Предлагаю продемонстрировать пример такого сервиса с применением библиотек, ставших классическими в мире NLP. Каждая библиотека обладает своими недостатками и преимуществами, но предлагаю не фокусироваться сейчас на этом, а рассмотреть пример из практики, но максимально облегченный.
Возьмём фразу и сделаем набор кода, который нам поможет проанализировать и получить нужные нам сущности и параметры:
"Добрый день, я, Сидоров Иван Иванович. Прошу перевести сто тысяч рублей Якову Петру Игнатьевичу"
Как обработать данную фразу?
Сценарий:
Собираем массив ФИО, где ФИО совпадающее с ФИО счета — платильщик, а второй элемент ФИО — получателя;
Определяем тип запроса: перевести, оплатить, пополнить баланс и т. п;
Находим сумма и её валюту, которую нужно перевести между счетами.
Код для извлечения ФИО
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. надеюсь количество опечаток было минимальным