Лемматизатор в грамматическом словаре
При лемматизации мы берем слово и получаем для него лемму - нормальную (начальную, словарную) форму: словарем - словарь. Для русского языка это означает, что существительное в любой грамматической форме приводится к форме именительного падежа. Для подавляющего большинства русских существительных нормальная форма также означает единственное число, хотя для некоторых существительных, не употребляющихся в единственном числе, это может быть и форма множественного числа: санками - санки. Русский лексикон сформирован таким образом, что названия словарных статей всегда соответствуют начальной форме существительного. Поэтому лемматизация может быть побочным продуктом морфологического анализа. Однако морфологический анализ сам по себе достаточно тяжел и требует наличия очень большой словарной базы. Поэтому в некоторых случаях полезным оказывается описанный лемматизатор - более компактный и простой, требующий минимум ресурсов и внешних зависимостей.
В некоторых приложениях может быть полезным расширить задачу лемматизации так, чтобы заменять уменьшительные и усилительные формы на нейтральные: саночками - саночки, или приводить деепричастия к форме инфинитива: катаясь - кататься. Это выходит за рамки данного алгоритма лемматизации, но может быть реализовано с помощью такого инструмента грамматического словаря, как тезаурус.
Где скачать библиотеку русского лемматизатора
Компоненты лемматизатора (динамическая библиотека и файл данных с моделью языка для MS Windows 32/64 бит и Linux 32/64 бит) и примеры его использования входят в состав SDK Грамматического Словаря. Исходные тексты библиотеки на C++ доступны в репозитории проекта. Для прототипирования NLP алгоритмов на Питоне есть библиотека rulemma, доступная на гитхабе.
Особенности реализации лемматизатора
Данный вариант лемматизатора имеет следующие особенности:
1. Аккуратная лемматизация русских слов - для всех словоформ, присутствующих в текущей версии словаря, лемматизация выполняется безошибочно. Если слово допускает неоднозначную лемматизацию (роем - рыть или рой), то лемматизатор может найти все альтернативные варианты начальной формы слова.
2. Минимальный объем потребляемой памяти, данные хранятся на диске в сжатом виде, после открытия базы она занимает в памяти около 1 Мб в экономном режиме (см. флаги sol_LoadLemmatizator).
3. Поддержка любых языков, реализованных в проекте, таким образом генерируемый при сборке англо-русского словаря лемматизатор будет работать и с английскими, и с русскими словами.
4. Встроенная вероятностная модель морфологии, обучаемая на эталонном корпусе, с помощью которой при лемматизации учитывается контекст слова и уменьшаться количество ошибочных результатов (см. функцию sol_LemmatizePhrase[W,A,8]).
5. Возможна лемматизация даже тех слов, которые отсутствуют в основном лексиконе. Это возможно благодаря тому, что в состав базы данных лемматизатора входят автоматически выводимые правила. Эти правила хорошо справляются с продуктивными суффиксами слов, используемыми в русском языке для образования новых слов.
На каких платформах выполняется лемматизация
Динамическая библиотека лемматизации lemmatizator.dll ( lemmatizator.so ) собирается для 32х и 64х битных платформ Windows и Linux, а также Mac OS X.
Для платформы .NET в состав SDK включена обертка lemmatizator_fx.dll и пример использования на C#.
Лемматизатор не требует наличия других библиотек из состава SDK, так как содержит все необходимые алгоритмы, словарную базу и вероятностную модель морфологии в двух своих файлах.
Очень простой API и отсутствие какой-либо привязки к C++ позволяет легко создавать обертки для вызова лемматизатора из других языков программирования.
Вероятностная лемматизация с учетом контекста
В лемматизатор входит вероятностная модель морфологии - обучаемая по специально размеченному корпусу числовая база данных. При первом обращении к функции sol_LemmatizePhrase[W,A,8] движок подгружает эту модель в оперативную память и затем использует ее для выбора более вероятной леммы. Увеличение точности, привносимое этой моделью, полностью определяется процессом обучения и ограничениями самой модели. В лабораторных условиях вероятностная модель морфологии позволяет улучшить точность примерно до 98-99%.
Для ранее упоминавшегося примера неоднозначной лемматизации роем - рой | рыть вероятностная модель стремится опереться на самое частотное употребление в контекста пчелиным роем - пчелиный рой или учесть синтаксические закономерности мы роем - я рыть (после личного местоимения в именительном падеже обычно идет личная форма глагола в соответствущей форме), рой улетел - рой улететь (после императива инфинитив употребляется только для некоторых модальных глаголов, в число которых рыть не входит).
Проиллюстрировать использование морфологической модели в лемматизаторе можно с помощью консольного отладчика Syntax. После его запуска введите директиву #lemmatize и затем предложение "мы ели суп, а вдоль аллеи стояли раскидистые ели". В этом предложении слово "ели" встречается два раза и представляет формы двух разных частей речи - глагола и существительного. Лемматизатор учтет эти факторы и выведет:
В результате первое вхождение слова приведено к инфинитиву "есть", второе - к форме именительного падежа единственного числа "ель".
Для использования вероятностной модели морфологии от прикладной программы не требуется никаких дополнительных действий, помимо вызова функции API sol_LemmatizePhrase[W,A,8]. Если модель морфологии отсутствует в базе данных, то данная функция будет работать фактически через вызов sol_GetLemmas[W,A,8] для каждого слова.
Ограничения вероятностной лемматизации определяются двумя основными факторами.
Во-первых, вероятностная модель не знает ничего о смысле слов, поэтому не всегда может заметить недопустимость применения похожего паттерна.
Во-вторых, алгоритм вероятностной модели учитывает только небольшую окрестность лемматизируемого слова. Поэтому синтаксические связи со словами за пределами данного учитываемого контекста игнорируются. Интересно отметить, что ограничение размера учитываемого контекста имеет и положительный эффект, а именно - это увеличивает устойчивость алгоритма к ошибкам в лемматизируемом предложении, и к появлению в нем неизвестных слов.
Отличие лемматизатора от функций морфологического разбора
Основное и единственное назначение лемматизатора - вернуть для исходного слова его базовую словарную форму. Например, для русских существительных это форма именительного падежа единственного числа, для глаголов - форма инфинитива. Существует и обратная операция - получение нужной грамматической формы слова из базовой, для существительных она называется склонение, для глаголов - спряжение.
В ходе морфологического разбора слова в качестве одного из "побочных" результатов также получается нормальная форма слова, благодаря тому, что морфологический анализатор распознает исходное слово как форму конкретной словарной статьи. Но в отличие от лемматизатора назначение морфологического разбора включает в себя получение множества другой информации о морфологических свойствах слова. Например, при морфологическом разборе существительного определяется его постоянные свойства (грамматические атрибуты) - перечислимость, одушевленность, род, и непостоянные (грамматические измерения) - падеж, число.
Таким образом, лемматизатор - это максимально упрощенный и оптимизированный морфологический анализатор. С точки зрения прикладного программиста использование лемматизатора тоже намного проще, если сравнивать с набором функций полного морфологического анализа. Среди заложенных конструктивных недостатков лемматизатора необходимо отметить то, что он ограниченно учитывает только ближайший контекст слова и таким образом не может сам выбрать часть речи, к которой необходимо нормализовать слово. Например, при лемматизации слова простынь получается две леммы - существительное простынь и глагол простыть. Если лемматизируемое слово употреблено в контексте, который известен встроенной модели морфологии, то лемматизатор выберет более частотный и, возможно, осмысленный вариант, иначе шансы на правильный результат будут определяться скорее случайными факторами, а именно порядком следования созданных при обучении правил. Морфологический анализатор текста умеет учитывать контекст слова и отбрасывать недопустимые варианты.
Unicode, ASCII и UTF-8 варианты функций
Некоторые функции API лемматизатора реализованы в 3х вариантах для удобства использования на разных платформах и языках программирования:
суффикс W - юникод, широкие строки (wchar_t, WideChar)
суффикс A - однобайтовая кодировка ASCII текущей локали
суффикс 8 - многобайтовая кодировка utf-8
Программный интерфейс лемматизатора
Открытие базы данныхHLEM sol_LoadLemmatizatorW ( const wchar_t * Filepath , int Flags )
HLEM sol_LoadLemmatizatorA ( const char * Filepath , int Flags )
HLEM sol_LoadLemmatizator8 ( const char * Filepath , int Flags )
Открывается база лемматизатора, созданная при компиляции словаря с опцией -save_lemmatizer.
Filepath - путь к базе лемматизатора, обычно в рамках проекта это файл lemmatizator.db.
Flags - дополнительные параметры для управления работы лемматизатором. Значение LEME_DEFAULT открывает базу в самом экономном, но самом медленном режиме лемматизации. При указании флага LEME_FASTER движок будет работать немного быстрее, несколько увеличив потребление памяти. Наконец, флаг LEME_FASTEST многократно ускорит лемматизацию, но загрузит базу данных в оперативную память, увеличив свои накладные расходы.
При любом значении флагов таблицы вероятностной модели загружаются только при первом вызове функции sol_LemmatizePhrase.
Возвращаемое значение является дескриптором объекта лемматизатора. Дескриптор указывается почти во всех остальных функциях API.
Удаление лемматизатораvoid sol_DeleteLemmatizator ( HLEM hEngine )
Закрывается база, подсоединенная предыдущим вызовом sol_LoadLemmatizator[W,A,8] . Освобождаенся память, занятая загруженными таблицами. Дескриптор hEngine становится невалидным и не должен более использоваться.
Лемматизация словаint sol_GetLemmaW ( HLEM hEngine , const wchar_t * Word , wchar_t * Result , int BufSize )
int sol_GetLemmaA ( HLEM hEngine , const char * Word , char * Result , int BufSize )
int sol_GetLemma8 ( HLEM hEngine , const char * Word , char * Result , int BufSize )
Выполняется лемматизация слова Word , результат копируется в буфер Result длиной BufSize символов. Слово представляет из себя цепочку символов, заканчивающуюся нулём.
Число вариантов лемматизации, если 1 - значит найдена и возвращена в буфере единственная нормальная форма, если > 1, то в буфер помещается какая-то первая из списка. Ниже описаны функции, которые могут работать со всеми вариантами лемматизации.
Для оценки количества слов, которые приводятся к более чем одной нормальной форме, можно воспользоваться словарем, загруженным в MS SQL и запросом:
Он дает такую табличку для русского лексикона:
Таким образом, доля слов, которые имеют более одной нормальной формы, не превышает 1%, если не учитывать частотность употребления слов в тексте.
HLEMMAS sol_GetLemmasW ( HLEM hEngine , const wchar_t * Word )
HLEMMAS sol_GetLemmasA ( HLEM hEngine , const char * Word )
HLEMMAS sol_GetLemmas8 ( HLEM hEngine , const char * Word )
Выполняется лемматизация слова Word и все альтернативные варианты возвращаются в виде дескриптора списка. Для работы с этим списком далее описано несколько функций.
Лемматизация фразы с учетом контекста каждого словаHLEMMAS sol_LemmatizePhraseW ( HLEM hEngine , const wchar_t * Sentence , int Flags , int WordSeparator )
HLEMMAS sol_LemmatizePhraseA ( HLEM hEngine , const char * Sentence , int Flags , int WordSeparator )
HLEMMAS sol_LemmatizePhrase8 ( HLEM hEngine , const char * Sentence , int Flags , int WordSeparator )
Выполняется лемматизация слов в предложении Sentence с учетом контекста каждого слова. Возвращается список выбранных лемм, по одному самому вероятному варианту для каждого слова.
Аргумент Flags в текущей версии должен всегда задаваться как 0.
Аргумент WordSeparator должен передавать код широкого символа (wchar_t), который использован для разделения слов в фразе. Обратите внимание, что задача токенизации, то есть разбивка на слова, должна быть предварительно выполнена прикладным кодом самостоятельно. Лемматизатор берет из входной строки все символы, ограниченные заданным символом WordSeparator или началом/концом строки, и рассматривает их как одно слово.
Работа со списком леммint sol_CountLemmas ( HLEMMAS hList )
Возвращает количество элементов в списке лемматизаций hList .
int sol_CountLemmas ( HLEMMAS hList )
Возвращает количество элементов в списке лемматизаций hList .
int sol_GetLemmaStringW ( HLEMMAS hList , int Index , wchar_t * Result , int Bufsize )
int sol_GetLemmaStringA ( HLEMMAS hList , int Index , char * Result , int Bufsize )
int sol_GetLemmaString8 ( HLEMMAS hList , int Index , char * Result , int Bufsize )
Копирование в предоставленный буфер Result размером BufSize строки с индексом Index из списка лемматизаций hList .
void sol_DeleteLemmas ( HLEMMAS hList )
Удаляется список нормальных форм, возвращенный sol_GetLemmasX .
Функции PHP лемматизации
function Lemmatize ( $ word )
Возвращает лемму для слова-аргумента, символы должны быть в кодировке cp1251.
function LemmatizePhrase ( $ str )
Возвращает лемматизированную строку - каждое слово из входной строки проходит нормализацию. Текст должен быть в кодировке cp1251.
Пример использования
В составе SDK Грамматического Словаря есть исходный код примера вызова вышеописанных процедур для C++ и C#, а также проекты для VisualStudio и make-файлы для сборки примеров.
Основной пример на C++ располагается в подкаталоге . \demo\ai\solarix\Grammar_Engine\Lemmatizator\C . Пример компилируется для всех поддерживаемых платформ - 32- и 64-битных Windows, Linux и Mac OS X. Он имеет двойное назначение.
Во-первых, он демонстрирует использование всех функций API лемматизатора.
Во-вторых, он проверяет корректность приведения слов к базовым формам по эталонным спискам. Сами эти списки экспортированы из SQL хранилища словаря с помощью несложных запросов, и содержат исчерпывающий перечень для двух случаев - когда слово приводится однозначно к единственной лемме, и когда слово является формой двух словарных статей. Например, список слов, которые лемматизируются двумя альтернативными путями, используется такой запрос для MS SQL:
Результаты выполнения запроса выгружаются прямо из SQL Server Management Studio в текстовый файл, в кодировке utf-8.