Время прочтения: 3 мин.
Для работы с текстом методами ML и NLP нам нужно провести предобработку исходных данных. Методов для этого существует несколько, расскажем о лемматизации или приведении словоформы к лемме — её нормальной (словарной) форме.
Задача лемматизации может решаться несколькими путями, основные из них:
- Алгоритмический. Может привести к нормальной форме любое слово, но не исключены ошибки. Пример: алгоритмы, использующие стеммер Портера.
- С использованием базы данных лемм и словоформ. Исключает ошибки, но может не найти слово и вернуть пустой результат.
- Комбинированный. Самый эффективный, в случае если слова нет в базе, алгоритм пытается вычислить лемму сам.
Для языка python разработано несколько библиотек для лемматизации. К сожалению, большинство из них не поддерживают русский язык, а если и поддерживают, то дают неудовлетворительный результат. К таким библиотекам можно отнести nltk(nltk.stem.snowball), spacy (spacy.lang.ru).
Более подробно мы разберём две библиотеки, хорошо работающие с русским языком комбинированным методом, а именно: открытую pymorphy2 и закрытую разработку яндеса pymystem3.
pymorphy2 написан полностью на python, а pymystem3 является исполняемым файлом с консольным интерфейсом, для работы с ним в python будем использовать обёртку Mystem. Такие различия в архитектуре наталкивают на мысли о разнице в производительности с различными объемами текста и на различных ОС. Проверим наши догадки пролемматизируя книгу Анджея Сапковского «Ведьмак: Последнее желание»!
Считаем книгу, уберем знаки препинания и слова короче 4-х букв:
book = []
with open('./sapkovskiy_andzhey_poslednee_zhelanie.txt', 'r', encoding='utf-8', newline='\n', errors='ignore') as resf:
line = resf.readline()
while line:
line = re.sub(r'[^\w\s]', '', line)
line = re.sub(r'[\s]', ' ', line)
line = line.split()
line = list(filter(lambda x: len(x) > 3, line))
if len(line) > 0:
book.append(line)
line = resf.readline()
Пример замера скорости лемматизации:
start_time = datetime.now()
res_book = []
morph = pymorphy2.MorphAnalyzer()
for line in book:
res_line = []
for word in line:
res_line.append(morph.parse(word)[0].normal_form)
res_book.append(' '.join(res_line))
print(str(datetime.now() - start_time))
open('./pymorphy2.txt', 'w', encoding='utf-8').writelines("\n".join(res_book))
В качестве тестового стенда будет выступать ПК с intel i5-4430, 16 Gb Ram, Windows 10. В качестве Linux будем использовать WSL на этом же ПК.
Сравнение скорости работы:
Windows 10 | Linux (WSL) | |
pymorphy2 (по словам) | 2с. | 9 с. |
pymystem3 (по словам) | 9 мин. 11 с. | 7 с. |
pymystem3 (по предложениям) | 25 с. | 4 с. |
pymystem3 (по 50000 слов) | 0,007 с. | 0,003 с. |
Обратите внимание на изменение времени выполнения pymystem3 от обрабатываемого объёма за один вызов, это связанно с архитектурой решения, требующей запуск консольного приложения, что очень дорого по времени.
pymorphy2, в свою очередь, умеет работать только с одним словом за один вызов, поэтому в таблице представлен только этот вариант.
Сравнение результатов:
Оригинал | pymorphy2 | pymystem3 |
Она пришла под утро. | прийти утро | приходить утро |
– Я бы хотел здесь. | хотеть здесь | хотеть здесь |
– Что подать? | подать | подавать |
Выводы
Обе библиотеки хороши в работе, но если у вас на входе достаточно большой объем данных лучше будет обратить внимание на pymystem3 и, по возможности, использовать Linux, если объём не большой, то хорошим выбором станет pymorphy2.