Pull to refresh

NLP: проверка правописания — взгляд изнутри (часть 2)

Reading time6 min
Views3.8K
(Часть 1) Сегодня мы поговорим об уровнях понимания текстов нашей системой, о том, какие ошибки правописания отловить просто, какие не очень просто, а какие запредельно сложно.

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



Ошибки тоже могут возникать на разных уровнях. Можно ошибиться в линейной структуре — дважды напечатать одно и то же слово, забыть точку, круглую скобку и тому подобные вещи. То есть ошибка возникает в процессе выстраивания слов в цепочку, и человек вряд ли совершает её по незнанию какого-либо грамматического правила. Вероятно, речь идёт о простой невнимательности. Впрочем, на уровне цепочек можно выявить и некоторые настоящие грамматические ошибки. Скажем, в английском тексте не должно встречаться сочетаний «was been» — должно быть либо «was», либо «has been».

Но всё-таки настоящая грамматика начинается на уровне анализа сети понятий. Скажем, в нашем примере про собак подлежащее «я» должно сочетаться в лице и числе с глаголом «люблю» независимо от взаимного расположения этих слов в предложении. Разумеется, это соображение не отменяет необходимости отлавливать и более простые ошибки, выявленные на уровне линейной структуры.

Первые уровни

Вполне разумно начинать проверку ошибок с самых простых. Если что-то можно отловить на уровне банального поиска подстрок, зачем подклчюать тяжёлую артиллерию? Самая простая функциональность — это список автозамены, существующий и в MS Word. Речь идёт об очевидных опечатках, исправляемых системой автоматически, даже без подтверждения пользователя: abbout -> about, amde -> made, compleatly -> completely. Быть может, автозамена кажется настолько очевидной функцией, что вроде бы и говорить о ней смысла нет, однако мне как активному пользователю MS Word автозамена частенько помогает, и я буду рад видеть автозамену и в других текстовых процессорах. Для этого и работаем, в конце концов.

Немногим сложнее простые правила на основе регулярных выражений, рассматривающие текст как одну большую строку. На сегодняшний день мы отлавливаем регулярными выражениями простые ситуации, связанные с типографическими шероховатостями: пробел(ы) между знаками препинания, лишние пробелы между словами, нестандартные сочетания вроде "!?" и так далее. В принципе, даже на уровне простого поиска подстрок можно найти некоторое количество ошибок, пропускаемых спелл-чекером.

Предложения и токены

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

Как и всё в нашем мире, со второго взгляда задача разбиения текста на предложения уже не кажется столь простой. Очевидный алгоритм состоит в поиске завершающего предложение знака препинания, за которым следует заглавная буква. При этом мы будем ошибаться, встретив имя человека: «Как заявил М. Иванов, ...» Аналогичным образом на пути встают сокращения, в которых встречается точка. В принципе, можно добавить в анализатор список имён и сокращений, но это решение всё равно не будет лишено недостатков. Например, его придётся полностью переписывать для любого нового языка, где действуют свои правила окончания предложений. Кроме того, существует очевидная неувязка: мы ведь исходим из того, что входной текст содержит ошибки (в их исправлении и суть нашего модуля); так как же в условиях некорректного входа разбивать текст на предложения? В этом случае мы автоматически теряем возможность увидеть ошибку на стыке предложений. Если считать, что граница пролегает между точкой и заглавной буквой, то ошибка вида «забыли поставить заглавную букву» сразу окажется вне досягаемости, ибо система попросту не поймёт, что в данном месте находится граница предложений.

Сейчас наиболее популярные подходы к разбиению текста на предложения в реальных условиях заключаются в использовании алгоритмов классификации на основе machine learning.

Sentence splitter

Коротко говоря, задача классификации состоит в том, чтобы определить корректный класс объекта C на основе его атрибутов (A1, ..., An). На вход обучающемуся алгоритму даётся большая выборка известных объектов, на основе которой он формирует своё представление о том, как значения атрибутов влияют на принадлежность объекта к тому или иному классу. Затем можно подать на вход алгоритму набор атрибутов неизвестного объекта и получить наиболее вероятный его класс.

Хрестоматийный пример задачи классификации — определение вида цветка ириса на основе четырёх параметров — длины и ширины лепестка и чашелистика. Существует три вида ириса: Iris setosa, Iris virginica и Iris versicolor. В наборе данных Iris перечислено 50 записей следующего вида:



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

Классификатор может использоваться и для других целей: принятие решения на основе таблицы эталонных решений в условиях тех или иных обстоятельств, а также выявление скрытых закономерностей — ещё один хрестоматийный пример предполагает изучение «атрибутов» выживших при крушении Титаника пассажиров с тем, чтобы понять, каковы были шансы различных групп людей (ребёнок/взрослый, мужчина/женщина, пассажир/член команды, владелец билета 1/2/3 класса).

Существует масса различных алгоритмов классификации: decision trees, nearest neighbor, bayesian network, maximum entropy model, linear regression… Каждый имеет свои достоинства и недостатки. Некоторые лучше работают с числовыми данными, другие проще программировать, третьи скоростнее, четвёртые формулируют выявленные правила классификации в удобном для анализа виде.

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

Какие здесь есть тонкости? Во-первых, здесь мы имеем не совсем стандартную постановку задачи классификации. У нас на входе получаются только контексты концов предложения:

(A1, ..., An) -> (конец предложения)

В классической постановке база знаний должна включать в себя все варианты, т.е.:

(A1, ..., An) -> (конец предложения)
(A1, ..., An) -> (не конец предложения)

В нашем случае впихивать в таблицу все примеры не-концов предложения слишком разорительно — база разрастётся неимоверно. Видимо, по этой причине самый часто цитируемый автор machine learning-схемы (применительно к нашей задаче) A. Ratnaparkhi использовал принцип максимальной энтропии. Эта модель позволяет просто спросить вероятность принадлежности объекта к данному классу вне связи с другими возможными классами. Иначе говоря, мы спрашиваем у модели, какова вероятность данного контекста быть концом предложения. Если алгоритм отвечает, что вероятность выше 1/2, можно отметить контекст как границу предложений.

Я думаю, что имеет смысл испробовать и другие алгоритмы классификации. Насколько знаю, этого не было сделано; если руки дойдут — займусь. Эксперименты же Ratnaparkhi показывают точность его алгоритма в районе 98%, то есть из ста концов предложений он угадывает 98 правильно.

К сожалению, в модуле проверки правописания мы снова сталкиваемся с тем, что входной текст может содержать ошибки. Если натренировать модель на разбитых на предложения корректных текстах, компьютер справедливо решит, что предложение всегда начинается с заглавной буквы. Если же выбросить «заглавность» из учитываемых атрибутов, точность модели упадёт. Можно вручную внести несколько ошибок в эталонные тексты (кое-где «забыть» точку, кое-где заменить заглавную букву строчной). Далее, в системе Ratnaparkhi мы сначала должны найти потенциальную границу предложений, а потом уже спросить систему о её мнении относительно этого места. У него это делается просто: ищем точку, восклицательный или вопросительный знак — и спрашиваем, что здесь такое. У нас же пользователь может забыть о точке — и что делать?

На сегодняшний день помимо знаков препинания я проверяю ещё символы перевода строки (по личному опыту — если я где и забываю поставить точку, так это в конце абзаца). Можно попытаться изучать все пробелы между словами, но боюсь, что точность может упасть. В общем, здесь есть о чём подумать :)

Ладно, на сегодня хватит, продолжим в следующий раз.
Tags:
Hubs:
+44
Comments12

Articles