- PVSM.RU - https://www.pvsm.ru -

Эволюция алгоритма Test The Text

Test The Text [1] выделяет стоп-слова в тексте. Стоп-слова делают текст тяжелее, слабее, длиннее.

Стоп-слова делятся на несколько категорий:
— модальные глаголы;
— усиляющие и обобщенные определения и наречия;
— клише и канцеляризмы;
— гиперонимы;
— паразиты времени;
— отглагольные существительные;
— пассивный залог;
— наречия;
— причастные обороты.

Прототип выделял модальные глаголы, используя список «мочь», «долженствовать» и «нуждаться» во всех формах:

    'modal': {
        'can': u"""могу, мог, могла, можешь, может, могло, можем, можете, могли, могут, 
                        смог, смогла, смогли, сможет, можно, нужен""",
        'need': u'нуждаться, нуждается, нужно, нужна, нужны',
        'should': u'должен, должна, должны, должно',
        'other': u'стоит, обязан, следует, необходимо, требуется'
    },

Текст разбивался на слова регулярным выражением (?:[s,.:]|A|Z), каждое слово сравнивалось со стоп-словами. Совпадения помечались в исходном тексте <span class=«класс стоп-слова»>, размеченный текст возвращался обратно и заменял текст на странице.

Прототип работал, список стоп-слов рос, но когда я добрался до клише, понял, что дальше перечислять стоп-слова во всех формах я не смогу. Каждое стоп-слово превращалось в 63. Три рода × три времени × семь падежей. Я подключил pystemmer [2].

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

нуждаться → нужда
инновационное → инновацион

высокий → высок
высокая → высок
высокую → высок

Pystemmer работает по алгоритму Snowball [3].

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

К сожалению, через словари стоп-слов невозможно проверить наречия, пассивный залог и причастные обороты. Представляете себе список всех наречий русского языка? Пришло время подключать морфологический анализатор. Выбора для python, кроме pymorphy2 [4] от kmike [5] нет, поэтому останавливаюсь на нем.

Морфологический анализатор определяет для слова часть речи (существительное, глагол, прилагательное, ...), пол, единственное/множественное число, падеж, лицо, время, залог для глаголов. Полный список в исходниках [6]. Захватывающая статья [7] как устроен pymoprhy2.

[Parse(word=u'доставлен', tag=OpencorporaTag('PRTS,perf,past,pssv masc,sing'), normal_form=u'доставить', score=1.0, methods_stack=((<DictionaryAnalyzer>, u'доставлен', 745, 71),))]

[Parse(word=u'пищущие', tag=OpencorporaTag('ADJF plur,nomn'), normal_form=u'пищущий', score=0.212962962962963, methods_stack=((<DictionaryAnalyzer>, u'ищущие', 162, 20), (<UnknownPrefixAnalyzer>, u'п'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('ADJF inan,plur,accs'), normal_form=u'пищущий', score=0.212962962962963, methods_stack=((<DictionaryAnalyzer>, u'ищущие', 162, 24), (<UnknownPrefixAnalyzer>, u'п'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,tran,pres,actv plur,nomn'), normal_form=u'пискать', score=0.212962962962963, methods_stack=((<DictionaryAnalyzer>, u'ищущие', 1609, 33), (<UnknownPrefixAnalyzer>, u'п'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,tran,pres,actv inan,plur,accs'), normal_form=u'пискать', score=0.212962962962963, methods_stack=((<DictionaryAnalyzer>, u'ищущие', 1609, 37), (<UnknownPrefixAnalyzer>, u'п'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,intr,pres,actv plur,nomn'), normal_form=u'питать', score=0.03703703703703704, methods_stack=((<FakeDictionary>, u'пищущие', 1670, 33), (<KnownSuffixAnalyzer>, u'щущие'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,intr,pres,actv inan,plur,accs'), normal_form=u'питать', score=0.03703703703703704, methods_stack=((<FakeDictionary>, u'пищущие', 1670, 37), (<KnownSuffixAnalyzer>, u'щущие'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,tran,pres,actv plur,nomn'), normal_form=u'пистать', score=0.03703703703703704, methods_stack=((<FakeDictionary>, u'пищущие', 2631, 33), (<KnownSuffixAnalyzer>, u'щущие'))), 
Parse(word=u'пищущие', tag=OpencorporaTag('PRTF,impf,tran,pres,actv inan,plur,accs'), normal_form=u'пистать', score=0.03703703703703704, methods_stack=((<FakeDictionary>, u'пищущие', 2631, 37), (<KnownSuffixAnalyzer>, u'щущие')))]

После подключения морфологического анализатора Test The Text выделяет наречия, страдательный залог, причастный оборот и, заодно, междометия.

Осталось разобраться с проблемами на клиенте. Я и не подозревал, что с простым полем ввода текста может быть столько проблем. Пришлось написать java-script очистки текста при вставке и код вставки <br> по нажатию enter. В новой версии я заменил свой код на Wysihtml5 [8]. Wysihtml5 это легковесный html-редактор. Нашел его, изучая как сделали редактор в Basecamp.

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

Вместо этого сервер стал возвращать список стоп-слов с их классом, начальной и конечной позицией. А разметка уже происходила на клиенте. Если слово на позиции не совпадает с ответом от сервера, слово не помечается. На тот случай, если пользователь поменял текст и позиция слова сместилась.

Планы по развитию:
— Выделение предложений больше 17 слов, их трудно читать.
— Выделение абзацев длиннее 8 строчек. Скорее всего такие абзацы нужно разбить.
— Слежение за «ритмом [9]» текста. В хорошем тексте длинные предложения чередуются со средними и короткими, текст становится не монотонным. Читатель не засыпает.
— Повторение слов в сосендних предложениях.
— Сослагательное наклонение.
— Публичное API.


Подписывайтесь на наш Хабра-блог [10] и полезные письма [11]. Пишем о информационном стиле, разбираем чужие посты.

Автор: TestTheText

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/50025

Ссылки в тексте:

[1] Test The Text: http://test-the-text.ru

[2] pystemmer: https://pypi.python.org/pypi/PyStemmer/1.0.1

[3] Snowball: http://snowball.tartarus.org/texts/introduction.html

[4] pymorphy2: https://github.com/kmike/pymorphy2

[5] kmike: http://habrahabr.ru/users/kmike/

[6] исходниках: https://github.com/kmike/pymorphy2/blob/master/pymorphy2/tagset.py

[7] Захватывающая статья: http://habrahabr.ru/post/176575/

[8] Wysihtml5: http://xing.github.io/wysihtml5/

[9] ритмом: http://lib.rus.ec/b/259930/read#t13

[10] Хабра-блог: http://habrahabr.ru/company/ttt/

[11] полезные письма: http://eepurl.com/Jntoz

[12] Источник: http://habrahabr.ru/post/204898/