Skip to main content

ruMorph

ruMorph

Russian Morphology - быстрый морфологический анализатор русского языка на Rust с API для Python

Документация · PyPI · English

Версия Поддерживаемые версии Python Сборка Ruff Лицензия


ruMorph - морфологический анализатор русского языка: ядро на Rust и API для Python. Для словоформы анализатор находит по словарю OpenCorpora варианты разбора - начальную форму (лемму), часть речи и признаки Universal Dependencies - упорядочивает их по вероятности и строит формы слова.

Разбор и лемматизация примерно в 5 раз быстрее, чем в pymorphy3 с ускорением pymorphy3[fast], форма по признакам и согласование с количеством - в 15-18 раз; списки слов разбираются без GIL. Части речи, признаки и леммы следуют соглашениям трибанка SynTagRus, поэтому результат можно сравнивать с разметкой spaCy, Stanza и других инструментов на UD.

  • Анализатор - разборы словоформы по убыванию вероятности, разбор списков слов и лемматизация без GIL, проверка словоформы по словарю
  • Части речи и признаки UD - части речи, признаки и леммы в соглашениях SynTagRus; пометы OpenCorpora, у которых нет признака UD
  • Токены вне словаря - числа, знаки, латиница, инициалы и сокращения по правилам
  • Незнакомые слова - разборы по окончанию, слова через дефис и с приставками, формы угаданных слов
  • Словоизменение - формы лексемы, форма по признакам UD, согласование с количеством
  • Переход с pymorphy - соответствие вызовов pymorphy2 и pymorphy3, частей речи и граммем
  • Скорость и память - разбор, лемматизация и словоизменение в сравнении с pymorphy3, загрузка словаря и память

Установка

Требуется Python 3.11 или новее.

pip install rumorph

Или с помощью uv:

uv add rumorph

Колеса собираются для Linux, macOS и Windows, Rust для установки не нужен; словарь входит в пакет. На других платформах и на Python 3.14t без GIL pip соберет пакет из исходников - для этого нужен Rust 1.88 или новее. Подробнее - на странице Установка.

Быстрый старт

>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> morph.lemmatize("Мы стали друзьями в ковиде".split())
['мы', 'стать', 'друг', 'в', 'ковид']
>>> [(a.lemma, a.pos, a.feats.get("Case"), round(a.prob, 3)) for a in morph.analyze("стали")][:2]
[('стать', 'VERB', None, 0.975), ('сталь', 'NOUN', 'Gen', 0.011)]
>>> morph.analyze("кошка")[0].inflect(Case="Gen", Number="Plur")
'кошек'
>>> morph.analyze("рубль")[0].agree(5)
'рублей'

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

Возможности

Разбор словоформы

Метод analyze возвращает разборы словоформы по убыванию вероятности - объекты Analysis с леммой, частью речи, признаками UD, пометами словаря, вероятностью и источником разбора. Регистр не важен, буква «е» может обозначать «ё». Разборы неизменяемы: их можно сравнивать, класть в множества и сохранять через pickle.

>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> morph.analyze("стали")[0]
Analysis(word='стали', lemma='стать', pos='VERB', feats='Aspect=Perf|Mood=Ind|Number=Plur|Tense=Past|VerbForm=Fin|Voice=Mid', labels='intr', prob=0.9753459013836056, source='dictionary')
>>> [len(analyses) for analyses in morph.analyze_many(["мама", "мыла", "раму"])]
[1, 4, 2]
>>> morph.is_known("Ежи"), morph.is_known("вайб")
(True, False)

Списки слов методы analyze_many и lemmatize разбирают без GIL, поэтому несколько потоков с одним анализатором работают параллельно. Анализатор и разборы сохраняются через pickle и работают с multiprocessing и joblib.

Подробнее - в документации: анализатор, разбор словоформы.

Части речи и признаки Universal Dependencies

Части речи и признаки следуют Universal Dependencies в соглашениях крупнейшего русского трибанка UD_Russian-SynTagRus. Отличия от частей речи OpenCorpora:

  • «который», «этот», «свой», «весь», «такой» и другие местоименные прилагательные - DET
  • «быть» и «бы» - AUX
  • вводные слова «однако», «например», «конечно» - ADV
  • «можно», «надо», «нельзя» - VERB без признаков
  • предлоги - ADP, сочинительные союзы - CCONJ, подчинительные - SCONJ, частицы - PART

Признаки: падеж, число, род, одушевленность, лицо, время, вид, наклонение, залог, форма глагола, степень, краткая форма, тип имени собственного, сокращение, притяжательность, тип числительного и его запись, тип местоимения, возвратность, несклоняемость, отрицание. Леммы тоже следуют SynTagRus: «Ивановой» - «иванова», «важнейшей» - «важнейший», «денег» - «деньги». Граммемы OpenCorpora, для которых в UD нет признака, - стиль, переходность, второй предложный падеж и другие - лежат в пометах labels.

>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> words = ["который", "был", "конечно", "можно", "Ивановой", "денег"]
>>> [(analyses[0].lemma, analyses[0].pos) for analyses in morph.analyze_many(words)]
[('который', 'DET'), ('быть', 'AUX'), ('конечно', 'ADV'), ('можно', 'VERB'), ('иванова', 'PROPN'), ('деньги', 'NOUN')]
>>> lesu = morph.analyze("лесу")[0]
>>> lesu.feats["Case"], lesu.labels
('Loc', frozenset({'loc2'}))

Подробнее - в документации; соответствие граммем OpenCorpora признакам UD - на странице Переход с pymorphy.

Токены вне словаря

Числа, знаки, латиницу и сокращения анализатор разбирает по правилам, source у таких разборов - "rule":

  • знаки препинания - PUNCT, символы %, $, № и эмодзи - SYM
  • числа цифрами - NUM; целое число может быть и порядковым ADJ, у годов это первый разбор
  • числа с окончанием «2005-го», «5-ти» - порядковые ADJ с падежом или количественные NUM, римские числа - порядковые ADJ
  • слова латиницей - X с Foreign=Yes
  • инициалы «А.» - имя, отчество или фамилия с Abbr=Yes
  • сокращения с точкой «т.», «им.» - разборы словарного сокращения, аббревиатуры капсом «НКО» - PROPN или NOUN с Abbr=Yes
  • наречия «по-бурятски», «по-молодому» - ADV
  • прочие токены «км/ч», «РосПил» - X без признаков, лемма - токен в нижнем регистре

Доли неоднозначных разборов взяты из частот в SynTagRus.

>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> [(a.lemma, a.pos, a.feats["NumType"], round(a.prob, 2)) for a in morph.analyze("2026")]
[('2026', 'ADJ', 'Ord', 0.94), ('2026', 'NUM', 'Card', 0.06)]
>>> [(a.lemma, a.pos, a.feats["Case"]) for a in morph.analyze("2005-го")][:1]
[('2005-й', 'ADJ', 'Gen')]
>>> [(a.pos, a.feats, a.source) for a in morph.analyze("iPhone")]
[('X', {'Foreign': 'Yes'}, 'rule')]

Подробнее - в документации.

Незнакомые слова

Разборы слова кириллицей, которого нет в словаре, анализатор угадывает по окончанию: берет формы словарных слов с тем же окончанием - их часть речи, признаки и словоизменение. source у таких разборов - "guess".

  • Слово в нижнем регистре угадывается как нарицательное, слово с заглавной буквы - в основном как имя собственное: фамилия, имя, топоним
  • Слово через дефис разбирается по последней части: «крэш-тестов» - «крэш-тест», «Мак-Киннона» - «мак-киннон»
  • Слово с известной приставкой - «эко», «анти», «супер», «микро» и другими - разбирается по словарному слову без нее: «экодомов» - «экодом»
  • У угаданного разбора есть формы, и они сохраняют заглавные буквы: «Мак-Киннона» в дательном падеже - «Мак-Киннону»
>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> [(a.lemma, a.pos, a.feats["Case"], a.source) for a in morph.analyze("чатботу")][:1]
[('чатбот', 'NOUN', 'Dat', 'guess')]
>>> guess = morph.analyze("Мартова")[0]
>>> guess.lemma, guess.pos, guess.feats["NameType"], guess.inflect(Case="Dat")
('мартов', 'PROPN', 'Sur', 'Мартову')
>>> morph.analyze("крэш-тестов")[0].lemma, morph.analyze("экодомов")[0].lemma
('крэш-тест', 'экодом')

Подробнее - в документации.

Словоизменение

Каждый разбор знает свою лексему - все формы слова с той же леммой:

  • forms - формы лексемы в порядке словаря
  • inflect - форма с заданными признаками UD; признаки, которые не названы, по возможности сохраняются
  • agree - форма существительного, прилагательного или причастия, согласованная с количеством: «1 рубль», «2 рубля», «5 рублей», «2 суток»

Если у лексемы нет нужной формы, inflect и agree бросают FormNotFoundError, а на опечатку в признаке inflect бросает ValueError со списком допустимых значений.

>>> from rumorph import Analyzer

>>> morph = Analyzer()
>>> cat = morph.analyze("кошка")[0]
>>> [form.word for form in cat.forms()][:5]
['кошка', 'кошки', 'кошке', 'кошку', 'кошкой']
>>> cat.inflect(Case="Gen"), cat.inflect(Case="Gen", Number="Plur")
('кошки', 'кошек')
>>> verb = morph.analyze("читал")[0]
>>> verb.inflect(Gender="Fem"), verb.inflect(Tense="Pres", Person="3", Number="Plur")
('читала', 'читают')
>>> ruble = morph.analyze("рубль")[0]
>>> [f"{n} {ruble.agree(n)}" for n in (1, 2, 5, 21)]
['1 рубль', '2 рубля', '5 рублей', '21 рубль']

Подробнее - в документации.

Переход с pymorphy

ruMorph работает с тем же словарем OpenCorpora, что pymorphy2 и pymorphy3, но API у него свое: части речи и признаки UD вместо граммем OpenCorpora, вероятность вместо score, словоформы строкой, исключения вместо None. Здесь morph - анализатор, p - разбор pymorphy, a - разбор ruMorph:

pymorphy2, pymorphy3 ruMorph
MorphAnalyzer() Analyzer()
morph.parse(word) morph.analyze(word)
[morph.parse(w)[0].normal_form for w in words] morph.lemmatize(words)
morph.word_is_known(word) morph.is_known(word)
p.normal_form, p.tag.POS, p.score a.lemma, a.pos, a.prob
p.tag.case, p.tag.number a.feats.get("Case"), a.feats.get("Number")
p.lexeme a.forms()
p.inflect({"gent", "plur"}).word a.inflect(Case="Gen", Number="Plur")
p.make_agree_with_number(n).word a.agree(n)

Подробнее - в документации: все вызовы, части речи и граммемы.

Скорость и память

Тысяч слов или разборов в секунду, больше - лучше:

Операция ruMorph pymorphy3 pymorphy3[fast]
Разбор словоформы 474 20 105
Лемматизация 810 22 170
Лемматизация в 4 потоках 2 345 - -
Форма по признакам 1 400 76 76
Согласование с количеством 1 307 85 85

Импорт и загрузка словаря занимают 14 мс против 30 мс у pymorphy3, прирост памяти процесса - 21,5 МБ против 25,5 МБ у pymorphy3[fast]. Замер - на 128 251 словоформе тестовой части UD_Russian-SynTagRus, Apple M3 Pro, Python 3.11.

Подробнее - в документации: все операции и как они измерены.

Разработка

Проект использует uv для управления зависимостями, maturin для сборки модуля на Rust и ruff для линтинга и форматирования. Нужен Rust 1.88 или новее.

git clone https://github.com/SergeyShk/ruMorph.git
cd ruMorph

make deps        # создать окружение, установить зависимости и собрать модуль на Rust
make dictionary  # собрать словарь из pymorphy3-dicts-ru
make test        # запустить тесты Python, примеры из докстрингов (doctest) и тесты Rust
make lint        # ruff, mypy, rustfmt и clippy

Полный список команд - make help. Документация двуязычная: русские страницы docs/*.md, английские - docs/*.en.md рядом с ними; при правке страницы обновляйте обе версии.

Перед отправкой изменений стоит установить хуки, которые прогонят линтеры на коммите и тесты на пуше:

uv run pre-commit install

Участие в проекте

Баг-репорты, идеи и пул-реквесты приветствуются - issues открыты. Как устроен процесс и что проверить перед отправкой пул-реквеста - в CONTRIBUTING.md; правила общения - в кодексе поведения.

Структура проекта
  • crates/rumorph - ядро анализатора на Rust: формат словаря, сборка, разбор и словоизменение
  • crates/rumorph-build - сборка словаря из выгрузки pymorphy3-dicts-ru и перевод тегов OpenCorpora в UD
  • crates/rumorph-py - модуль Python rumorph._rumorph на PyO3
  • python/rumorph - пакет Python
  • scripts - выгрузка словаря pymorphy3-dicts-ru и проверка установленного пакета перед публикацией
  • docs - документация MkDocs на русском и английском
  • tests - тесты пакета Python

Авторы

Лицензия

Код распространяется под лицензией MIT. Словарь в пакете собран из словаря OpenCorpora и распространяется по лицензии CC BY-SA 3.0 (LICENSE-DICTIONARY.txt).

Цитирование

Если вы используете ruMorph в исследованиях или программах, пожалуйста, цитируйте библиотеку по следующей записи BibTeX - это помогает развитию и поддержке проекта. Те же метаданные лежат в CITATION.cff - GitHub показывает их по кнопке «Cite this repository».

@software{ruMorph,
  author = {Sergey Shkarin},
  title = {{ruMorph, a fast morphological analyzer for Russian}},
  year = 2026,
  url = {https://github.com/SergeyShk/ruMorph}
}

Metadata

Release files for rumorph 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rumorph 0.1.0
File Size Uploaded Provenance
rumorph-0.1.0.tar.gz 6.5 MB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for rumorph 0.1.0
File
rumorph-0.1.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
rumorph-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
rumorph-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
rumorph-0.1.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
rumorph-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 39.9 MB

Release files / rumorph-0.1.0.tar.gz

Download URL rumorph-0.1.0.tar.gz
Size 6.5 MB
Tags Source
SHA-256 checksum
How to use checksums
a6621f1b1609a63862bdf2a2f37b528a131fb59931dd02b6057545ca4621513f
BLAKE2b-256 checksum
How to use checksums
eadb8d430539babd7914aa4219712272e1e3d88ed477f2050638d7ad5ee59317
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / rumorph-0.1.0-cp311-abi3-win_amd64.whl

Download URL rumorph-0.1.0-cp311-abi3-win_amd64.whl
Size 6.6 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
a9b993577325bc62090e0840be9914149df2686636f979627325d53a2a000274
BLAKE2b-256 checksum
How to use checksums
c565ab2bafc6d45f869e0026e310f154982eedd5260255c77a95a178a0af5cf5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / rumorph-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL rumorph-0.1.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 6.7 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
78b011101fbf27a28f0cff72fc65b7367584d9cc8e3092cb4b9bc0356f4a5a42
BLAKE2b-256 checksum
How to use checksums
c1a19f53d9330e972f362a82d1f84bf616c614426dc778f62ad8eb5f59c1e170
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / rumorph-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL rumorph-0.1.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 6.7 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
46891b29a00a24dc07dfab39b334674e44d729be82783b25534ca449e71f6e04
BLAKE2b-256 checksum
How to use checksums
8d451ff70d0ab27628e1aab0adb8e084b7ce4f31f29c05a186b19c863338165a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / rumorph-0.1.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL rumorph-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
Size 6.7 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
fc6bf580e2e943de791c574d6cb209e3a22909c681d5903ccc457827397d4725
BLAKE2b-256 checksum
How to use checksums
f53839c288665607bac90d616c74d3e6255be42e2fd9ded6b99e5d150c5d88b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / rumorph-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL rumorph-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 6.7 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
fcaebae876e7f211c9c1ded69d52d73ca16bfa99a7006fc97435dbbc6da4f532
BLAKE2b-256 checksum
How to use checksums
7a9985d4bd1555a373742c3768625b6ddd0f52c635e8ebe7e87a26abd44b3a6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for rumorph 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

6 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page