Время прочтения: 4 мин.
Для решения задач обработки текстов на естественном языке на сегодняшний день существует множество библиотек для python. В данной статье обратимся к библиотеке Stanza от StanfordNLPGroup, основанной на PyTorch. И, т.к. анализ текста является важной NLP-задачей, рассмотрим основные методы, реализованные в данной библиотеке.
Для установки библиотеки используем команду pip install stanza.
Для работы с русскоязычным текстом скачиваем соответствующую модель:
import stanza
stanza.download('ru')
Теперь рассмотрим различные этапы анализа (предобработки) текстовых данных.
1. Токенизация.
Разобьём текст на предложения (sentences) и предложения на токены (tokens)
import stanza
ppln = stanza.Pipeline('ru', processors='tokenize') #инициируем нейронный конвеер (Pipeline)
txt = 'Об орясину осёл топорище точит. А факир выгнав гостей выть акулой хочет.'
doc = ppln(txt)
for i, sentence in enumerate(doc.sentences):
print(f'====== Предложение {i+1} =======')
print(*[f'id: {token.id}\ttext: {token.text}' for token in sentence.tokens], sep='\n')
Получаем следующий список предложений и токенов:
====== Предложение 1 =======
id: (1,) text: Об
id: (2,) text: орясину
id: (3,) text: осёл
id: (4,) text: топорище
id: (5,) text: точит
id: (6,) text: .
====== Предложение 2 =======
id: (1,) text: А
id: (2,) text: факир
id: (3,) text: выгнав
id: (4,) text: гостей
id: (5,) text: выть
id: (6,) text: акулой
id: (7,) text: хочет
id: (8,) text: .
2. POS-tagging
Теперь проведём пример с частеречной разметкой (part of speech tagging). При инициализации Pipeline в параметр processors добавляем значение ‘pos’. В качестве результата выводим соответствующие частям речи значения (тэги) в формате universalPOS (upos), а так же дополнительные лексические и грамматические свойства в формате universalmorphologicalfeatures (UFeats)
import stanza
ppln = stanza.Pipeline('ru', processors='tokenize,pos')
txt = 'Об орясину осёл топорище точит. А факир выгнав гостей выть акулой хочет.'
doc = ppln(txt)
print(*[f'word: {word.text}\tupos: {word.upos}\tfeats: {word.feats if word.feats else "_"}' for snt in doc.sentences for word in snt.words], sep='\n')
Результат будет следующим:
word: Об upos: ADP feats: _
word: орясину upos: NOUN feats: Animacy=Inan|Case=Loc|Gender=Masc|Number=Sing
word: осёл upos: NOUN feats: Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing
word: топорище upos: NOUN feats: Animacy=Inan|Case=Nom|Gender=Masc|Number=Sing
word: точит upos: VERB feats: Aspect=Imp|Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin|Voice=Act
word: . upos: PUNCT feats: _
word: А upos: CCONJ feats: _
word: факир upos: NOUN feats: Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing
word: выгнав upos: VERB feats: Aspect=Perf|Tense=Past|VerbForm=Conv|Voice=Act
word: гостей upos: NOUN feats: Animacy=Anim|Case=Acc|Gender=Masc|Number=Plur
word: выть upos: VERB feats: Aspect=Imp|VerbForm=Inf|Voice=Act
word: акулой upos: NOUN feats: Animacy=Anim|Case=Ins|Gender=Fem|Number=Sing
word: хочет upos: VERB feats: Aspect=Imp|Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin|Voice=Act
word: . upos: PUNCT feats:
3. Лемматизация.
Для получения нормальных словарных форм слов, необходимо при инициализации Pipeline в параметр processors добавить значение ‘lemma’. И в результат выводим свойство lemma каждого слова (word).
import stanza
ppln = stanza.Pipeline('ru', processors='tokenize,pos,lemma')
txt = 'Об орясину осёл топорище точит. А факир выгнав гостей выть акулой хочет.'
doc = ppln(txt)
print(*[f'word: {word.text}\tupos: {word.lemma}' for snt in doc.sentences for word in snt.words], sep='\n')
Результатом выполнения кода будет:
word: Об upos: о
word: орясину upos: орясина
word: осёл upos: осел
word: топорище upos: топорищ
word: точит upos: точить
word: . upos: .
word: А upos: а
word: факир upos: факир
word: выгнав upos: выгнать
word: гостей upos: гость
word: выть upos: выть
word: акулой upos: акула
word: хочет upos: хотеть
word: . upos: .
4 Анализ зависимостей.
По аналогии с предыдущими пунктами добавляем в параметр processors значение ‘depparse’ при инициализации Pipeline. Обработчик depparse строит дерево зависимостей между словами предложений.
import stanza
ppln = stanza.Pipeline('ru', processors='tokenize,pos,lemma,depparse')
txt = 'Об орясину осёл топорище точит. А факир выгнав гостей выть акулой хочет.'
doc = ppln(txt)
print(*[f'word: {word.text}\thead: {snt.words[word.head-1].text if word.head > 0 else "root"}\tdeprel: {word.deprel}' for snt in doc.sentences for word in snt.words], sep='\n')
В результате видим список с зависимостями — каждому слову сопоставляется вершина и тип синтаксического отношения (deprel) в формате Universal Dependencies:
word: Об head id: 2 head: орясину deprel: case
word: орясину head id: 5 head: точит deprel: obl
word: осёл head id: 5 head: точит deprel: nsubj
word: топорище head id: 3 head: осёл deprel: appos
word: точит head id: 0 head: root deprel: root
word: . head id: 5 head: точит deprel: punct
word: А head id: 7 head: хочет deprel: cc
word: факир head id: 7 head: хочет deprel: nsubj
word: выгнав head id: 7 head: хочет deprel: advcl
word: гостей head id: 3 head: выгнав deprel: obj
word: выть head id: 3 head: выгнав deprel: xcomp
word: акулой head id: 5 head: выть deprel: obl
word: хочет head id: 0 head: root deprel: root
word: . head id: 7 head: хочет deprel: punct
В данной статье мы рассмотрели инструментарий библиотеки Stanza по анализу (предобработке) текстовых данных.
С учетом мультиязычности данный проект может составить серьёзную конкуренцию другим NLP-библиотекам на python.