Компоненты¶
StatsComponent(nlp, name)
Основа компонентов spaCy, которые кладут статистики текста в расширение Doc: компонент регистрирует расширение при добавлении в пайплайн и кладет статистики каждого документа в doc._.<name>. Разработка компонентов в целом описана в документации spaCy.
Компоненты ruTS - подклассы StatsComponent ядра anyTS, по одному на каждый класс статистик.
Примечание
Примеры ниже используют рекомендуемый конвейер на модели ru_core_news_sm, которая ставится отдельно: python -m spacy download ru_core_news_sm (см. установку).
import ruts
nlp = ruts.load_pipeline()
nlp.add_pipe("ruts_basic", name="basic")
nlp("мама мыла раму")._.basic.c_letters
nlp("?!")._.basic is None
{4: 3}
True
Параметры¶
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
nlp |
Language |
- | Пайплайн, в который добавляется компонент |
name |
str |
- | Имя компонента в пайплайне и расширения |
Оба параметра задает spaCy при nlp.add_pipe(factory, name=...), остальные параметры компонента передаются словарем config того же вызова.
Имена¶
Фабрики носят префикс ruts_ (таблица ниже и компонент границ предложений ruts_blank_lines). Они объявлены точками входа spacy_factories, поэтому spaCy находит их без import ruts, а пайплайн, сохраненный с ними (nlp.to_disk(path)), загружается через spacy.load(path).
Имя компонента в пайплайне - это имя расширения: nlp.add_pipe(factory, name="basic") кладет статистики в doc._.basic. Без name компонент и расширение получают имя фабрики. Расширение следует за компонентом, когда пайплайн переименовывает его (nlp.rename_pipe). Имя, занятое расширением другого пакета, дает ParameterError вместо замены: при add_pipe или на первом документе после rename_pipe, который переименовывает компонент раньше, чем тот узнает свое имя. Компонент, взятый из другого пайплайна (add_pipe(name, source=other)), - один и тот же объект в обоих, поэтому под новым именем он пишет и в то расширение в другом пайплайне; отдельный компонент дает фабрика, add_pipe(factory, name=...). Один и тот же компонент можно добавить дважды под разными именами, с разными параметрами. Документ без слов - пустая строка, пробелы, одни знаки препинания - проходит компонент нетронутым, а его расширение остается None.
У ruts_lexical нетронутым проходит и документ из одних чисел, у ruts_verse - документ без букв.
Сериализация
Компонент кладет в doc._.<name> объект класса статистик, который spaCy сериализовать не умеет: Doc.to_bytes(), DocBin(store_user_data=True) и nlp.pipe(..., n_process>1) с такими компонентами в пайплайне завершатся ошибкой. Для сохранения документа исключайте пользовательские данные (doc.to_bytes(exclude=["user_data"])) или сохраняйте doc._.<name>.get_stats() отдельно; для многопроцессной обработки считайте статистики в основном процессе после nlp.pipe, без компонентов.
Добавление компонента расширяет токенизатор spaCy правилами для приклеенных к словам тире реплик (ruts.utils.add_dash_rules), чтобы тире реплик отделялось от слова, как в строке; пайплайну без компонентов ruTS эту функцию нужно вызвать самому. Токенизатор anySeg рекомендуемого конвейера компоненты не меняют.
Знаки ударения ruTS снимает со слов Doc, но модель разбирает такие слова хуже: на тексте после accentuate у теггера ru_core_news_sm меняется часть речи больше половины слов, а зависимости меняются и в рекомендуемом конвейере. Текст с ударениями передавайте в пайплайн без них - nlp(ruts.utils.strip_marks(text)).
Рекомендуемый конвейер¶
load_pipeline(model='ru_core_news_sm', exclude=(), **kwargs)
Конвейер spaCy, в котором Doc размечается так же, как строка, кроме слов через дефис вроде «муж-то» и «два-три»: строка делит их на части, а в Doc это одно слово. Токены и предложения дает сегментатор anySeg, части речи, признаки и леммы - морфологический анализатор ruMorph в контексте предложения, а модель - парсер зависимостей и распознавание сущностей. Сохраненный такой конвейер загружается как есть. То же вручную:
nlp = spacy.load(
"ru_core_news_sm",
exclude=["morphologizer", "lemmatizer"],
config={"nlp": {"tokenizer": {"@tokenizers": "anyseg.Tokenizer.v1"}}},
)
nlp.add_pipe("anyseg_sentencizer", first=True)
nlp.add_pipe("rumorph", after="anyseg_sentencizer")
На UD SynTagRus такой конвейер точнее самой модели: часть речи верна у 97,3 % слов против 93,3 %, зависимость с отношением (LAS) - у 82,7 % против 82,1 %. Обычный spacy.load("ru_core_news_sm") тоже поддерживается, но части речи, признаки и предложения тогда дает модель, и статистики Doc могут расходиться со статистиками строки. Ошибки ее теггера ruTS не обходит: коннекторы вроде «значит» и «т.е.» она размечает глаголом и знаком препинания, и они не находятся (на TextsByGrade и SovChLit - 11 на 71 тыс. слов), а «боишься» - инфинитивом, и придаточная с ним считается инфинитивной клаузой.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
model |
str |
"ru_core_news_sm" |
Имя или путь модели spaCy: ru_core_news_sm, ru_core_news_md, ru_core_news_lg |
exclude |
str, list[str] |
() |
Еще компоненты модели, которые не загружаются, например ner |
**kwargs |
- | - | Остальные параметры spacy.load; токенизатор в config заменяется на anySeg |
from ruts import load_pipeline
pipeline = load_pipeline()
pipeline.pipe_names
[(token.text, token.pos_, token.lemma_) for token in pipeline("Нож из стали.")]
['anyseg_sentencizer', 'rumorph', 'tok2vec', 'parser', 'attribute_ruler', 'ner']
[('Нож', 'NOUN', 'нож'), ('из', 'ADP', 'из'), ('стали', 'NOUN', 'сталь'), ('.', 'PUNCT', '.')]
Компоненты классов статистик¶
| Компонент | Фабрика | Класс статистик | Параметры |
|---|---|---|---|
BasicStatsComponent |
ruts_basic |
BasicStats |
- |
MorphStatsComponent |
ruts_morph |
MorphStats |
- |
ReadabilityStatsComponent |
ruts_readability |
ReadabilityStats |
preset, basic |
UnadaptedReadabilityStatsComponent |
ruts_unadapted_readability |
UnadaptedReadabilityStats |
basic |
DiversityStatsComponent |
ruts_diversity |
DiversityStats |
window_len, mtld_threshold, mtld_min_len, hdd_sample_size, log_base |
StyleStatsComponent |
ruts_style |
StyleStats |
stopwords, top_n, nausea_stopwords, cliches |
PhonStatsComponent |
ruts_phon |
PhonStats |
window_len |
SyntaxStatsComponent |
ruts_syntax |
SyntaxStats |
- |
CohesionStatsComponent |
ruts_cohesion |
CohesionStats |
blank_lines |
LexicalStatsComponent |
ruts_lexical |
LexicalStats |
data_dir |
VerseStatsComponent |
ruts_verse |
VerseStats |
data_dir |
Основные статистики¶
BasicStatsComponent(nlp, name)
BasicStatsComponent кладет основные статистики документа в его расширение.
Морфологические статистики¶
MorphStatsComponent(nlp, name)
MorphStatsComponent кладет в расширение морфологические статистики; по умолчанию перед ним нужны части речи.
В ruTS части речи и признаки берутся из разметки пайплайна (token.pos_, token.morph), а без нее - из разбора ruMorph по слову.
nlp.add_pipe("ruts_morph", name="morph")
nlp("мама мыла раму")._.morph.case
('Nom', None, 'Acc')
Метрики удобочитаемости¶
ReadabilityStatsComponent(nlp, name, preset=None, basic=None)
ReadabilityStatsComponent кладет в расширение метрики удобочитаемости, посчитанные по документу или, с basic, по основным статистикам, которые положил в него другой компонент. Библиотека задает basic_factory - фабрику своего компонента основных статистик, которую называет ошибка, если в том расширении их нет.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
preset |
str |
None |
Пресет коэффициентов, один из пресетов класса; если None - пресет класса по умолчанию |
basic |
str |
None |
Расширение компонента основных статистик, которые берутся вместо повторного подсчета |
Если preset оставлен None, конфигурация сохраненного пайплайна не содержит пресета, и загруженный пайплайн берет пресет класса по умолчанию; библиотека, которой нужно записать в конфигурацию свой пресет по умолчанию, задает его в сигнатуре своего подкласса.
Исключения:
ParameterError-stats_class, который не конкретный класс, пресет, который не строка или не пресет класса, расширение, имя которого не строка;SourceTypeError- класс безbasic_stats_classи безbasic;SourceError- документ, в расширенииbasicкоторого нет основных статистик класса.
Пресеты ruTS - plainrussian (по умолчанию), fiction и academic. В ruTS ошибок stats_class и SourceTypeError не бывает, а сообщение SourceError называет компонент ruts_basic, который нужно добавить перед ним.
nlp.add_pipe("ruts_readability", name="readability")
config = {"preset": "fiction", "basic": "basic"}
nlp.add_pipe("ruts_readability", name="readability_fiction", config=config)
doc = nlp("Кот сидел на окне и смотрел на птиц, которые летали над крышами домов.")
doc._.readability.flesch_kincaid_grade
doc._.readability_fiction.flesch_kincaid_grade
-0.1506153846153886
6.41769230769231
Формулы других языков¶
UnadaptedReadabilityStatsComponent(nlp, name, basic=None)
UnadaptedReadabilityStatsComponent кладет в расширение формулы удобочитаемости других языков, посчитанные по документу или, с basic, по основным статистикам, которые положил в него другой компонент. Библиотека задает basic_factory, как для ReadabilityStatsComponent.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
basic |
str |
None |
Расширение компонента основных статистик, которые берутся вместо повторного подсчета |
Исключения:
ParameterError-stats_class, который не конкретный класс, расширение, имя которого не строка;SourceTypeError- класс безbasic_stats_classи безbasic;SourceError- документ, в расширенииbasicкоторого нет основных статистик класса.
Формулы - UnadaptedReadabilityStats с исходными коэффициентами, без калибровки под русский язык; ошибки в ruTS - как у ReadabilityStatsComponent.
nlp.add_pipe("ruts_unadapted_readability", name="unadapted", config={"basic": "basic"})
doc = nlp("Кот сидел на окне и смотрел на птиц, которые летали над крышами домов.")
doc._.unadapted.gulpease, doc._.unadapted.forcast
doc._.unadapted.bs is doc._.basic
(69.0, 13.076923076923077)
True
Метрики лексического разнообразия¶
DiversityStatsComponent(nlp, name, window_len=50, mtld_threshold=0.72, mtld_min_len=10, hdd_sample_size=42, log_base=10)
DiversityStatsComponent кладет в расширение метрики лексического разнообразия, посчитанные классом библиотеки, который читает Doc. Его параметры - параметры DiversityStats с теми же значениями по умолчанию.
Исключения:
ParameterError- неверный параметр (check_paramsразнообразия).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
window_len |
int |
50 |
Размер окна для MATTR и сегмента для MSTTR |
mtld_threshold |
float |
0.72 |
Порог TTR для MTLD, MA-MTLD и MTLD-W |
mtld_min_len |
int |
10 |
Минимальная длина фактора для MTLD, MA-MTLD и MTLD-W |
hdd_sample_size |
int |
42 |
Размер выборки для HD-D |
log_base |
float |
10 |
Основание логарифма для метрик Summer, Maas и Dugast |
config = {"window_len": 100, "log_base": 2.718281828459045}
nlp.add_pipe("ruts_diversity", name="diversity", config=config)
nlp("мама мыла раму")._.diversity.rttr
1.7320508075688774
SEO-метрики стиля¶
StyleStatsComponent(nlp, name, stopwords=None, top_n=10, nausea_stopwords=None, cliches=None)
StyleStatsComponent кладет в расширение метрики стиля.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
stopwords |
list[str] |
None |
Стоп-слова водности; если None - стоп-слова класса |
top_n |
int |
10 |
Количество самых частых слов академической тошноты и естественности по закону Ципфа (NAUSEA_TOP_N) |
nausea_stopwords |
list[str] |
None |
Слова, исключаемые из самых частых слов академической тошноты; если None - слова класса |
cliches |
list[str] |
None |
Штампы; если None - штампы класса (cliches_list) |
Исключения:
SourceTypeError- стоп-слова, стоп-слова тошноты или штампы, которые не список строк;ParameterError-top_n, который не целое число не меньше единицы.
Без списков слова «воды» и стоп-слова тошноты определяются по разметке ruMorph, а штампы берутся из OFFICIALESE_CLICHES.
nlp.add_pipe("ruts_style", name="style", config={"stopwords": ["и", "в", "не"], "top_n": 5})
nlp("мама мыла раму")._.style.water
nlp.add_pipe("ruts_style", name="style_cliches", config={"cliches": ["в целях", "в рамках"]})
nlp("В целях экономии в рамках проекта мы закрыли склад.")._.style_cliches.cliches
0.0
22.22222222222222
Фоностатистики¶
PhonStatsComponent(nlp, name, window_len=3)
PhonStatsComponent кладет в расширение фонетические статистики; window_len (по умолчанию PHON_WINDOW_LEN) - окно в словах для аллитерации и ассонанса.
Исключения:
ParameterError-window_len, который не целое число не меньше 2.
nlp.add_pipe("ruts_phon", name="phon", config={"window_len": 5})
nlp("мама мыла раму")._.phon.p_open_syllables
1.0
Синтаксические статистики¶
SyntaxStatsComponent(nlp, name)
SyntaxStatsComponent кладет в расширение синтаксические статистики; перед ним нужны парсер и части речи.
Парсер и части речи есть в рекомендуемом конвейере и в моделях ru_core_news_sm, ru_core_news_md и ru_core_news_lg.
Исключения:
SourceError- документ без разбора зависимостей или частей речи (rumorphрекомендуемого конвейера илиmorphologizerмодели).
nlp.add_pipe("ruts_syntax", name="syntax")
nlp("Дом, построенный рабочими в прошлом году, был продан")._.syntax.tree_depth
4.0
Статистики связности¶
CohesionStatsComponent(nlp, name, blank_lines=False)
CohesionStatsComponent кладет в расширение статистики связности. Парсер ему не нужен: Doc без границ предложений делится на предложения SentsExtractor. Части речи берутся из разметки, а леммы - из ruMorph по части речи токена; без разметки и то и другое дает разбор ruMorph, как у строки.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
blank_lines |
bool |
False |
Абзацы только после пустых строк - для текста, строки которого переносятся внутри абзаца; по умолчанию абзац - строка |
Исключения:
ParameterError-blank_linesнеbool.
nlp.add_pipe("ruts_cohesion", name="cohesion")
nlp.add_pipe("ruts_cohesion", name="paragraphs", config={"blank_lines": True})
doc = nlp("Кот сидел на окне. Он смотрел на птиц. Птицы улетели,\nи кот уснул.")
(
doc._.cohesion.noun_overlap_adjacent,
doc._.cohesion.n_paragraphs,
doc._.paragraphs.n_paragraphs,
)
(0.5, 2, 1)
Статистики лексической сложности¶
LexicalStatsComponent(nlp, name, data_dir=None)
LexicalStatsComponent кладет в расширение статистики лексической сложности. Метрикам частотного словаря нужен загруженный FreqDict; полосы и лексическая плотность считаются и без него.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
data_dir |
str |
None |
Путь к директории с частотным словарем; если не задан, используется директория по умолчанию |
Исключения:
DatasetNotFoundError- метрики частотного словаря иget_stats(), когдаFreqDictне загружен.
nlp.add_pipe("ruts_lexical", name="lexical")
nlp("Кот сидел на окне и смотрел на птиц")._.lexical.p_top1000
0.75
Стиховедческие статистики¶
VerseStatsComponent(nlp, name, data_dir=None)
VerseStatsComponent кладет в расширение стиховедческие статистики; ему нужен загруженный словарь ударений StressDict. Строки стиха - строки текста Doc, поэтому стихотворение передается в nlp без склейки строк. Текст с буквами, но без русских слов дает пустые статистики, как в VerseStats.
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
data_dir |
str |
None |
Путь к директории со словарем ударений; если не задан, используется директория по умолчанию |
Исключения:
DatasetNotFoundError- словарь ударений не загружен; ошибку дает первый документ с буквами.
nlp.add_pipe("ruts_verse", name="verse")
poem = (
"Буря мглою небо кроет,\nВихри снежные крутя;\n"
"То, как зверь, она завоет,\nТо заплачет, как дитя"
)
doc = nlp(poem)
doc._.verse.meter, doc._.verse.n_feet
('хорей', 4)
Предложения после пустых строк¶
start_sents_after_blank_lines(doc)
Компонент ставит начало предложения на первый токен после пустой строки - перевода строки, необязательных пробельных символов и еще одного перевода строки, - чтобы заголовок, пункт списка или абзац без конечного знака были отдельным предложением, как в экстракторе предложений. Он ставится перед парсером, senter или sentencizer, а тот сохраняет его начала и расставляет остальные. Пробельные символы перед таким началом остаются в предыдущем предложении, а знаки, которые открывают абзац (тире реплики, ¡, «), - при его первом слове. Сам по себе компонент предложения внутри абзаца не делит и ставит частичные границы (has_sents), поэтому статистики берут предложения такого документа из его текста. Разобранный документ, например повторно пропущенный через пайплайн, проходит нетронутым, потому что spaCy сохраняет его предложения. Языковая библиотека регистрирует компонент под своим префиксом: Language.component("<prefix>_blank_lines", func=start_sents_after_blank_lines).
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
doc |
Doc |
- | Объект Doc |
В ruTS компонент зарегистрирован как ruts_blank_lines. Без него парсер модели ru_core_news_sm склеивает абзац без конечного знака со следующим предложением; рекомендуемому конвейеру компонент не нужен.
import spacy
nlp = spacy.load("ru_core_news_sm")
nlp.add_pipe("ruts_blank_lines", before="parser")
[sent.text.strip() for sent in nlp("Что нового\n\nБыстрый импорт. Меньше ошибок").sents]
['Что нового', 'Быстрый импорт.', 'Меньше ошибок']