Перейти к содержанию

Анализатор

Analyzer(path=None)

Морфологический анализатор: для словоформы находит по словарю OpenCorpora все варианты разбора - начальную форму, часть речи и признаки Universal Dependencies - и упорядочивает их по вероятности. Словарь загружается при создании первого анализатора: анализаторы с тем же файлом словаря в процессе делят его, поэтому новый анализатор создается мгновенно. Последний загруженный словарь остается в процессе и без анализаторов, поэтому задачи пула процессов и анализатор, созданный на один вызов, не загружают словарь заново.

Исключения:

  • FileNotFoundError - нет файла словаря;
  • OSError - файл словаря не читается: нет доступа, путь указывает на каталог;
  • ValueError - файл не словарь ruMorph или поврежден;
  • TypeError - путь, который не строка и не PathLike.
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')

Параметры

Параметр Тип По умолчанию Описание
path str / PathLike None Путь к файлу словаря; по умолчанию - словарь из пакета

Объект хранит путь к словарю в path типа Path, только для чтения. Файл словаря отображается в память: процессы с одним файлом делят его память, поэтому каждый следующий процесс с анализатором занимает около 1,4 МБ. Пока анализатор существует, файл нельзя перезаписывать на месте, а заменить новым файлом можно; в Windows открытый файл не заменяется и не удаляется. Последний загруженный словарь остается открытым и после удаления анализаторов - до загрузки словаря из другого файла или выхода из процесса. Словарь - доверенные данные, как код: загрузка отвергает поврежденный файл, но не любой специально подделанный, поэтому словари из ненадежных источников загружать не стоит.

Методы

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

analyze · list[Analysis]

analyze(word)

Разборы словоформы по убыванию вероятности; сумма вероятностей равна 1. Регистр не важен, а буква «е» может обозначать «ё»: analyze("ЕЖ") возвращает разборы словоформы «ёж». Токен, которого нет в словаре, - число, знак, слово латиницей, сокращение - разбирается по правилам, а разборы незнакомого слова кириллицей угадываются по окончанию и по частям. Токен без пробелов и невидимых символов получает хотя бы один разбор: если ничего не подошло - X без признаков.

Параметр Тип По умолчанию Описание
word str - Словоформа

Исключения:

  • TypeError - слово, которое не строка.
[(a.lemma, a.pos, a.feats.get("Case"), round(a.prob, 3)) for a in morph.analyze("стали")]
[(a.lemma, a.source) for a in morph.analyze("чатботу")][:2]
[('стать', 'VERB', None, 0.975),
 ('сталь', 'NOUN', 'Gen', 0.011),
 ('сталь', 'NOUN', 'Nom', 0.005),
 ('сталь', 'NOUN', 'Dat', 0.003),
 ('сталь', 'NOUN', 'Loc', 0.003),
 ('сталь', 'NOUN', 'Acc', 0.003)]
[('чатбот', 'guess'), ('чатбота', 'guess')]

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

analyze_many · list[list[Analysis]]

analyze_many(words)

Разборы каждой словоформы, как у analyze; на списке метод быстрее, чем analyze в цикле.

Параметр Тип По умолчанию Описание
words Iterable[str] - Словоформы: список, кортеж, генератор

Исключения:

  • TypeError - строка вместо набора слов, слово, которое не строка.
[len(analyses) for analyses in morph.analyze_many(["мама", "мыла", "раму"])]
[1, 4, 2]

Лемматизация

lemmatize · list[str]

lemmatize(words)

Леммы самых вероятных разборов словоформ; токен без разборов возвращается в нижнем регистре.

Параметр Тип По умолчанию Описание
words Iterable[str] - Словоформы: список, кортеж, генератор

Исключения:

  • TypeError - строка вместо набора слов, слово, которое не строка.
morph.lemmatize("Мы стали друзьями в ковиде".split())
['мы', 'стать', 'друг', 'в', 'ковид']

Словоформа в словаре

is_known · bool

is_known(word)

Есть ли словоформа в словаре; регистр и «е» вместо «ё», как у analyze, не важны. Слова, разобранные по правилам или угаданные, в словаре не числятся.

Параметр Тип По умолчанию Описание
word str - Словоформа

Исключения:

  • TypeError - слово, которое не строка.
morph.is_known("Ежи"), morph.is_known("вайб")
(True, False)

Словарь

Словарь пакета собран из словаря OpenCorpora: около 3,1 млн словоформ. Вероятности разборов взяты из корпуса OpenCorpora: у слова, написанного через «е» вместо «ё», - частоты написания с «ё», у словоформ, которых в корпусе нет, разборы равновероятны. Словарь распространяется по лицензии CC BY-SA 3.0.

Потоки и процессы

Один анализатор можно использовать из нескольких потоков: analyze_many и lemmatize отпускают GIL и разбирают списки параллельно, а в Python 3.14t без GIL параллельно работают и analyze, is_known, inflect и agree. Общий анализатор не медленнее отдельного на каждый поток, поэтому заводить анализатор на поток не нужно. Без GIL потоки упираются в удаление объектов разборов: forms в потоках почти не ускоряется, а analyze_many на длинных списках - слабо, поэтому такие списки лучше разбирать кусками по тысяче-другой слов. Анализатор и разборы сохраняются через pickle, поэтому работают с multiprocessing и joblib: процессы делят отображенный в память словарь, сколько бы разборов они ни получили. Передача разборов между процессами дороже самого разбора, поэтому в процессах лучше получать леммы и поля разборов, а разборы - в потоках.

from concurrent.futures import ThreadPoolExecutor

texts = [["мама", "мыла", "раму"], ["кошки", "ловят", "мышей"]]
with ThreadPoolExecutor(2) as pool:
    lemmas = list(pool.map(morph.lemmatize, texts))
lemmas
[['мама', 'мыло', 'рама'], ['кошка', 'ловить', 'мышь']]