Named-entity recognition for russian language
Project description
Natasha solves basic NLP tasks for Russian language: tokenization, sentence segmentation, word embedding, morphology tagging, lemmatization, phrase normalization, syntax parsing, NER tagging, fact extraction. Quality on every task is similar or better then current SOTAs for Russian language on news articles, see evaluation section. Natasha is not a research project, underlying technologies are built for production. We pay attention to model size, RAM usage and performance. Models run on CPU, use Numpy for inference.
Natasha integrates libraries from Natasha project under one convenient API:
- Razdel — token, sentence segmentation for Russian
- Navec — compact Russian embeddings
- Slovnet — modern deep-learning techniques for Russian NLP, compact models for Russian morphology, syntax, NER.
- Yargy — rule-based fact extraction similar to Tomita parser.
- Ipymarkup — NLP visualizations for NER and syntax markups.
⚠ API may change, for realworld tasks consider using low level libraries from Natasha project. Models optimized for news articles, quality on other domain may be lower. To use old
NamesExtractor
,AddressExtactor
downgradepip install natasha<1 yargy<0.13
Install
Natasha supports Python 3.5+ and PyPy3:
$ pip install natasha
Usage
For more examples and explanation see Natasha documentation.
>>> from natasha import (
Segmenter,
MorphVocab,
NewsEmbedding,
NewsMorphTagger,
NewsSyntaxParser,
NewsNERTagger,
PER,
NamesExtractor,
Doc
)
#######
#
# INIT
#
#####
>>> segmenter = Segmenter()
>>> morph_vocab = MorphVocab()
>>> emb = NewsEmbedding()
>>> morph_tagger = NewsMorphTagger(emb)
>>> syntax_parser = NewsSyntaxParser(emb)
>>> ner_tagger = NewsNERTagger(emb)
>>> names_extractor = NamesExtractor(morph_vocab)
>>> text = 'Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав о решении властей Львовской области объявить 2019 год годом лидера запрещенной в России Организации украинских националистов (ОУН) Степана Бандеры. Свое заявление он разместил в Twitter. «Я не могу понять, как прославление тех, кто непосредственно принимал участие в ужасных антисемитских преступлениях, помогает бороться с антисемитизмом и ксенофобией. Украина не должна забывать о преступлениях, совершенных против украинских евреев, и никоим образом не отмечать их через почитание их исполнителей», — написал дипломат. 11 декабря Львовский областной совет принял решение провозгласить 2019 год в регионе годом Степана Бандеры в связи с празднованием 110-летия со дня рождения лидера ОУН (Бандера родился 1 января 1909 года). В июле аналогичное решение принял Житомирский областной совет. В начале месяца с предложением к президенту страны Петру Порошенко вернуть Бандере звание Героя Украины обратились депутаты Верховной Рады. Парламентарии уверены, что признание Бандеры национальным героем поможет в борьбе с подрывной деятельностью против Украины в информационном поле, а также остановит «распространение мифов, созданных российской пропагандой». Степан Бандера (1909-1959) был одним из лидеров Организации украинских националистов, выступающей за создание независимого государства на территориях с украиноязычным населением. В 2010 году в период президентства Виктора Ющенко Бандера был посмертно признан Героем Украины, однако впоследствии это решение было отменено судом. '
>>> doc = Doc(text)
#######
#
# SEGMENT
#
#####
>>> doc.segment(segmenter)
>>> display(doc.tokens[:5])
>>> display(doc.sents[:5])
[DocToken(stop=5, text='Посол'),
DocToken(start=6, stop=13, text='Израиля'),
DocToken(start=14, stop=16, text='на'),
DocToken(start=17, stop=24, text='Украине'),
DocToken(start=25, stop=30, text='Йоэль')]
[DocSent(stop=218, text='Посол Израиля на Украине Йоэль Лион признался, чт..., tokens=[...]),
DocSent(start=219, stop=257, text='Свое заявление он разместил в Twitter.', tokens=[...]),
DocSent(start=258, stop=424, text='«Я не могу понять, как прославление тех, кто непо..., tokens=[...]),
DocSent(start=425, stop=592, text='Украина не должна забывать о преступлениях, совер..., tokens=[...]),
DocSent(start=593, stop=798, text='11 декабря Львовский областной совет принял решен..., tokens=[...])]
#######
#
# MORPH
#
#####
>>> doc.tag_morph(morph_tagger)
>>> display(doc.tokens[:5])
>>> doc.sents[0].morph.print()
[DocToken(stop=5, text='Посол', pos='NOUN', feats=<Anim,Nom,Masc,Sing>),
DocToken(start=6, stop=13, text='Израиля', pos='PROPN', feats=<Inan,Gen,Masc,Sing>),
DocToken(start=14, stop=16, text='на', pos='ADP'),
DocToken(start=17, stop=24, text='Украине', pos='PROPN', feats=<Inan,Loc,Fem,Sing>),
DocToken(start=25, stop=30, text='Йоэль', pos='PROPN', feats=<Anim,Nom,Masc,Sing>)]
Посол NOUN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing
Израиля PROPN|Animacy=Inan|Case=Gen|Gender=Masc|Number=Sing
на ADP
Украине PROPN|Animacy=Inan|Case=Loc|Gender=Fem|Number=Sing
Йоэль PROPN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing
Лион PROPN|Animacy=Anim|Case=Nom|Gender=Masc|Number=Sing
признался VERB|Aspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Mid
, PUNCT
что SCONJ
...
######
#
# LEMMA
#
#######
>>> for token in doc.tokens:
>>> token.lemmatize(morph_vocab)
>>> display(doc.tokens[:5])
>>> {_.text: _.lemma for _ in doc.tokens}
[DocToken(stop=5, text='Посол', pos='NOUN', feats=<Anim,Nom,Masc,Sing>, lemma='посол'),
DocToken(start=6, stop=13, text='Израиля', pos='PROPN', feats=<Inan,Gen,Masc,Sing>, lemma='израиль'),
DocToken(start=14, stop=16, text='на', pos='ADP', lemma='на'),
DocToken(start=17, stop=24, text='Украине', pos='PROPN', feats=<Inan,Loc,Fem,Sing>, lemma='украина'),
DocToken(start=25, stop=30, text='Йоэль', pos='PROPN', feats=<Anim,Nom,Masc,Sing>, lemma='йоэль')]
{'Посол': 'посол',
'Израиля': 'израиль',
'на': 'на',
'Украине': 'украина',
'Йоэль': 'йоэль',
'Лион': 'лион',
'признался': 'признаться',
',': ',',
'что': 'что',
'пришел': 'прийти',
'в': 'в',
'шок': 'шок',
'узнав': 'узнать',
'о': 'о',
...
#######
#
# SYNTAX
#
######
>>> doc.parse_syntax(syntax_parser)
>>> display(doc.tokens[:5])
>>> doc.sents[0].syntax.print()
[DocToken(stop=5, text='Посол', id='1_1', head_id='1_7', rel='nsubj', pos='NOUN', feats=<Anim,Nom,Masc,Sing>),
DocToken(start=6, stop=13, text='Израиля', id='1_2', head_id='1_1', rel='nmod', pos='PROPN', feats=<Inan,Gen,Masc,Sing>),
DocToken(start=14, stop=16, text='на', id='1_3', head_id='1_4', rel='case', pos='ADP'),
DocToken(start=17, stop=24, text='Украине', id='1_4', head_id='1_1', rel='nmod', pos='PROPN', feats=<Inan,Loc,Fem,Sing>),
DocToken(start=25, stop=30, text='Йоэль', id='1_5', head_id='1_1', rel='appos', pos='PROPN', feats=<Anim,Nom,Masc,Sing>)]
┌──► Посол nsubj
│ Израиля
│ ┌► на case
│ └─ Украине
│ ┌─ Йоэль
│ └► Лион flat:name
┌─────┌─└─── признался
│ │ ┌──► , punct
│ │ │ ┌► что mark
│ └►└─└─ пришел ccomp
│ │ ┌► в case
│ └──►└─ шок obl
│ ┌► , punct
│ ┌────►┌─└─ узнав advcl
│ │ │ ┌► о case
│ │ ┌───└►└─ решении obl
│ │ │ ┌─└──► властей nmod
│ │ │ │ ┌► Львовской amod
│ │ │ └──►└─ области nmod
│ └─└►┌─┌─── объявить nmod
│ │ │ ┌► 2019 amod
│ │ └►└─ год obj
│ └──►┌─ годом obl
│ ┌─────└► лидера nmod
│ │ ┌►┌─── запрещенной acl
│ │ │ │ ┌► в case
│ │ │ └►└─ России obl
│ ┌─└►└─┌─── Организации nmod
│ │ │ ┌► украинских amod
│ │ ┌─└►└─ националистов nmod
│ │ │ ┌► ( punct
│ │ └►┌─└─ ОУН parataxis
│ │ └──► ) punct
│ └──────►┌─ Степана appos
│ └► Бандеры flat:name
└──────────► . punct
...
#######
#
# NER
#
######
>>> doc.tag_ner(ner_tagger)
>>> display(doc.spans[:5])
>>> doc.ner.print()
[DocSpan(start=6, stop=13, type='LOC', text='Израиля', tokens=[...]),
DocSpan(start=17, stop=24, type='LOC', text='Украине', tokens=[...]),
DocSpan(start=25, stop=35, type='PER', text='Йоэль Лион', tokens=[...]),
DocSpan(start=89, stop=106, type='LOC', text='Львовской области', tokens=[...]),
DocSpan(start=152, stop=158, type='LOC', text='России', tokens=[...])]
Посол Израиля на Украине Йоэль Лион признался, что пришел в шок, узнав
LOC──── LOC──── PER───────
о решении властей Львовской области объявить 2019 год годом лидера
LOC──────────────
запрещенной в России Организации украинских националистов (ОУН)
LOC─── ORG───────────────────────────────────────
Степана Бандеры. Свое заявление он разместил в Twitter. «Я не могу
PER──────────── ORG────
понять, как прославление тех, кто непосредственно принимал участие в
ужасных антисемитских преступлениях, помогает бороться с
антисемитизмом и ксенофобией. Украина не должна забывать о
LOC────
преступлениях, совершенных против украинских евреев, и никоим образом
не отмечать их через почитание их исполнителей», — написал дипломат.
11 декабря Львовский областной совет принял решение провозгласить 2019
ORG──────────────────────
год в регионе годом Степана Бандеры в связи с празднованием 110-летия
PER────────────
со дня рождения лидера ОУН (Бандера родился 1 января 1909 года). В
ORG
июле аналогичное решение принял Житомирский областной совет. В начале
ORG────────────────────────
месяца с предложением к президенту страны Петру Порошенко вернуть
PER────────────
Бандере звание Героя Украины обратились депутаты Верховной Рады.
PER──── LOC──── ORG───────────
Парламентарии уверены, что признание Бандеры национальным героем
PER────
поможет в борьбе с подрывной деятельностью против Украины в
LOC────
информационном поле, а также остановит «распространение мифов,
созданных российской пропагандой». Степан Бандера (1909-1959) был
PER───────────
одним из лидеров Организации украинских националистов, выступающей за
ORG─────────────────────────────────
создание независимого государства на территориях с украиноязычным
населением. В 2010 году в период президентства Виктора Ющенко Бандера
PER─────────── PER────
был посмертно признан Героем Украины, однако впоследствии это решение
LOC────
было отменено судом.
#######
#
# PHRASE NORM
#
#######
>>> for span in doc.spans:
>>> span.normalize(morph_vocab)
>>> display(doc.spans[:5])
>>> {_.text: _.normal for _ in doc.spans if _.text != _.normal}
[DocSpan(start=6, stop=13, type='LOC', text='Израиля', tokens=[...], normal='Израиль'),
DocSpan(start=17, stop=24, type='LOC', text='Украине', tokens=[...], normal='Украина'),
DocSpan(start=25, stop=35, type='PER', text='Йоэль Лион', tokens=[...], normal='Йоэль Лион'),
DocSpan(start=89, stop=106, type='LOC', text='Львовской области', tokens=[...], normal='Львовская область'),
DocSpan(start=152, stop=158, type='LOC', text='России', tokens=[...], normal='Россия')]
{'Израиля': 'Израиль',
'Украине': 'Украина',
'Львовской области': 'Львовская область',
'России': 'Россия',
'Организации украинских националистов (ОУН)': 'Организация украинских националистов (ОУН)',
'Степана Бандеры': 'Степан Бандера',
'Петру Порошенко': 'Петр Порошенко',
'Бандере': 'Бандера',
'Украины': 'Украина',
'Верховной Рады': 'Верховная Рада',
'Бандеры': 'Бандера',
'Организации украинских националистов': 'Организация украинских националистов',
'Виктора Ющенко': 'Виктор Ющенко'}
#######
#
# FACT
#
######
>>> for span in doc.spans:
>>> if span.type == PER:
>>> span.extract_fact(names_extractor)
>>> {_.normal: _.fact for _ in doc.spans if _.type == PER}
{'Йоэль Лион': Name(
first='Йоэль',
last='Лион'
),
'Степан Бандера': Name(
first='Степан',
last='Бандера'
),
'Петр Порошенко': Name(
first='Петр',
last='Порошенко'
),
'Бандера': Name(
last='Бандера'
),
'Виктор Ющенко': Name(
first='Виктор',
last='Ющенко'
)}
Evaluation
Segmentation
Natasha uses Razdel for text segmentation.
errors
— number of errors aggregated over 4 datasets, see Razdel evalualtion section for more info.
errors | time | |
---|---|---|
razdel.tokenize | 5439 | 9.898350 |
mystem | 12192 | 17.210470 |
spacy | 12288 | 19.920618 |
nltk.word_tokenize | 130119 | 12.405366 |
errors | time | |
---|---|---|
razdel.sentenize | 32106 | 21.989045 |
deeppavlov/rusenttokenize | 41722 | 32.535322 |
nltk.sent_tokenize | 60378 | 29.916063 |
Embedding
Natasha uses Navec pretrained embeddings.
precision
— Average precision over 4 datasets, see Navec evalualtion section for more info.
type | precision | init, s | disk, mb | ram, mb | vocab | |
---|---|---|---|---|---|---|
hudlit_12B_500K_300d_100q | navec | 0.825 | 1.0 | 50.6 | 95.3 | 500K |
news_1B_250K_300d_100q | navec | 0.775 | 0.5 | 25.4 | 47.7 | 250K |
ruscorpora_upos_cbow_300_20_2019 | w2v | 0.777 | 12.1 | 220.6 | 236.1 | 189K |
ruwikiruscorpora_upos_skipgram_300_2_2019 | w2v | 0.776 | 15.7 | 290.0 | 309.4 | 248K |
tayga_upos_skipgram_300_2_2019 | w2v | 0.795 | 15.7 | 290.7 | 310.9 | 249K |
tayga_none_fasttextcbow_300_10_2019 | fasttext | 0.706 | 11.3 | 2741.9 | 2746.9 | 192K |
araneum_none_fasttextcbow_300_5_2018 | fasttext | 0.720 | 7.8 | 2752.1 | 2754.7 | 195K |
Morphology
Natasha uses Slovnet morphology tagger.
accuracy
— accuracy on news dataset, see Slovnet evaluation section for more.
accuracy | init, s | disk, mb | ram, mb | speed, sents/s | |
---|---|---|---|---|---|
slovnet | 0.961 | 1.0 | 27 | 115 | 532.0 |
deeppavlov_bert | 0.951 | 20.0 | 1393 | 8704 | 85.0 (gpu) |
deeppavlov | 0.940 | 4.0 | 32 | 10240 | 90.0 (gpu) |
spacy | 0.919 | 10.9 | 89 | 579 | 30.6 |
udpipe | 0.918 | 6.9 | 45 | 242 | 56.2 |
Syntax
Natasha uses Slovnet syntax parser.
uas
, las
— accuracy on news dataset, see Slovnet evaluation section for more.
uas | las | init, s | disk, mb | ram, mb | speed, sents/s | |
---|---|---|---|---|---|---|
slovnet | 0.907 | 0.880 | 1.0 | 27 | 125 | 450.0 |
deeppavlov_bert | 0.962 | 0.910 | 34.0 | 1427 | 8704 | 75.0 (gpu) |
spacy | 0.876 | 0.818 | 10.9 | 89 | 579 | 31.6 |
udpipe | 0.873 | 0.823 | 6.9 | 45 | 242 | 56.2 |
NER
Natasha uses Slovnet NER tagger.
f1
— score aggregated over 4 datasets, see Slovnet evaluation section for more.
PER/LOC/ORG f1 | init, s | disk, mb | ram, mb | speed, articles/s | |
---|---|---|---|---|---|
slovnet | 0.97/0.91/0.85 | 1.0 | 27 | 205 | 25.3 |
deeppavlov_bert | 0.98/0.92/0.86 | 34.5 | 2048 | 6144 | 13.1 (gpu) |
deeppavlov | 0.92/0.86/0.76 | 5.9 | 1024 | 3072 | 24.3 (gpu) |
pullenti | 0.92/0.82/0.64 | 2.9 | 16 | 253 | 6.0 |
Support
- Chat — https://telegram.me/natural_language_processing
- Issues — https://github.com/natasha/natasha/issues
- Commercial support — http://lab.alexkuk.ru/natasha
Development
Tests:
make test
Package:
make version
git push
git push --tags
make clean package publish
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.