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

Статистики лексической сложности

LexicalStats(source, words_extractor=None, freq_dict=None)

Лексическая сложность (lexical sophistication) по образцу TAALES (Kyle, Crossley и Berger, 2018) - насколько редки слова текста: статистики по частотному словарю и его униграммной модели, доли частотных полос списка самых частых лемм и лексическая плотность. Статистики по словарю вычисляются при первом обращении, поэтому полосам и лексической плотности данные словаря не нужны.

Исключения:

  • SourceTypeError - словарь другого класса, чем у библиотеки, или, без freq_dict_class, словарь без lookup и ipm или его отсутствие; analyze, который дает не объекты LexicalWord;
  • SourceError - источник без слов.

В ruTS SourceTypeError дают также источник, который не строка и не Doc, и экстрактор другого типа, а метрики по словарю без загруженного словаря - DatasetNotFoundError.

В отличие от метрик лексического разнообразия, которые сравнивают слова текста между собой, здесь слова сравниваются с частотами языка (TAALES). Источник данных - текст или объект Doc библиотеки spaCy.

Класс расширяет LexicalStats ядра anyTS русским слоем: словарь - FreqDict Ляшевской и Шарова (freq_dict_class), ранги лемм и размер списка (rank, top_size) - из вшитого списка лемм Шарова (get_rank). Слова строки извлекает русский WordsExtractor или заданный экстрактор, который для Doc применяется к его тексту; без экстрактора слова Doc берутся из его токенов, а части дефисного слова, разрезанного spaCy, склеиваются. Числа (2020, 5.5, 3-й) словами не считаются. Леммы дает ruMorph: для Doc с разметкой частей речи - по части речи токена (ruts.utils.lemmatize), для строки - в контексте предложения, для Doc без разметки - так же в предложениях, слова которых совпадают со словами строки, а для остальных слов и с заданным экстрактором слов - по первому разбору. Ключи слов в словаре (keys, dictionary_keys) - леммы, приведенные к его соглашениям функцией dictionary_lemma: должна - должен, денег - деньги, ночью - ночь. Таблица print_stats и сообщения об ошибках - по-русски (LEXICAL_STATS_DESC и CORE_MESSAGES из ruts.constants).

from ruts import LexicalStats
from ruts.datasets import FreqDict

FreqDict().download()
ls = LexicalStats("Кот сидел на окне и смотрел на птиц")
ls.print_stats()
                       Статистика                       | Значение
-------------------------------------------------------------------
Доля слов, найденных в частотном словаре                |   1.00
Средняя частотность (ipm)                               | 8645.54
Средняя частотность знаменательных слов (ipm)           |  324.18
Средняя логарифмическая частотность (lg ipm)            |   3.07
Средняя логарифмическая частотность знаменательных слов |   2.32
Средний диапазон (R)                                    |  99.75
Средняя дисперсия (D)                                   |  95.12
Средний сюрпризал (бит)                                 |   9.74
Униграммная перплексия                                  |  856.21
Доля слов из топ-1000                                   |   0.75
Доля слов из топ-2000                                   |   0.88
Доля слов из топ-5000                                   |   1.00
Доля слов из топ-10000                                  |   1.00
Доля слов вне топ-10000                                 |   0.00
Лексическая плотность                                   |   0.62

Параметры

Параметр Тип По умолчанию Описание
source str / Doc - Источник данных
words_extractor WordsExtractor None Инструмент для извлечения слов; применяется и к Doc, к его тексту
freq_dict FreqDict None Частотный словарь; по умолчанию FreqDict() из директории по умолчанию

Атрибуты

Атрибут Тип Описание
freq_dict FrequencyDictionary Частотный словарь
words, lemmas tuple[str] Слова и их леммы; полосы считаются по леммам
keys tuple[str] Ключи слов в словаре
entries tuple[FrequencyEntry / None] Статьи словаря, None для слова вне его
ranks tuple[int / None] Ранги лемм, None вне списка
n_words, n_content_words, n_found int Количество слов, знаменательных слов и слов, найденных в словаре

В ruTS словарь - FreqDict, а его статьи - именованные кортежи Entry.

Метрики

Каждая метрика - атрибут или свойство объекта, а get_stats дает их все. Среднее берется по словам, найденным в словаре, а без них равно nan.

Метрика Что измеряет Диапазон Чем больше, тем
coverage Доля слов, найденных в словаре 0-1 больше слов знакомо словарю
mean_ipm, mean_ipm_content Средняя частотность на миллион слов найденных слов, найденных знаменательных слов больше 0 частотнее слова
mean_log_ipm, mean_log_ipm_content Средний десятичный логарифм частотности найденных слов, найденных знаменательных слов до 6 частотнее слова
mean_range Средний диапазон найденных слов от 0 в большем числе частей корпуса встречаются слова
mean_dispersion Средняя дисперсия найденных слов как у словаря по мере словаря
surprisal Средний сюрпризал слов по униграммной модели словаря в битах от 0 реже слова
perplexity 2 в степени сюрпризала от 1 реже слова
p_top1000, p_top2000, p_top5000, p_top10000 Доля слов с леммой из топ-1000, 2000, 5000 и 10000 списка 0-1, nan для полосы больше top_size частотнее слова
p_beyond_top10000 Доля слов с леммой вне топ-10000 0-1, nan для списка короче 10000 реже слова
lexical_density Доля знаменательных слов 0-1 больше знаменательных слов

Метрики считаются по двум ресурсам; рядом со средними по словарю всегда смотрите coverage.

Ресурс Метрики Доступность
FreqDict - словарь Ляшевской и Шарова, 52 138 лемм с ipm, R, D coverage, mean_ipm*, mean_log_ipm*, mean_range, mean_dispersion, surprisal, perplexity загружается один раз командой FreqDict().download()
Вшитый список 10 000 самых частых лемм интернет-корпуса Лидского университета (С. А. Шаров, зеркало hingston/russian, CC BY 2.5) p_top1000, p_top2000, p_top5000, p_top10000, p_beyond_top10000, band_coverage всегда

Частотность по словарю

coverage · mean_ipm · mean_ipm_content · mean_log_ipm · mean_log_ipm_content · mean_range · mean_dispersion · Ляшевская, Шаров

Метрики считаются по статьям FreqDict для ключей слов (keys, entries): средние берутся по словам, найденным в словаре, по всем или только по знаменательным. Средняя частотность в ipm чувствительна к служебным словам (и - 35 000 ipm, в - 31 000), поэтому для сравнения текстов удобнее логарифм частотности или средняя по знаменательным словам. Средняя частотность знаменательных слов mean_ipm_content - признак FREQ2 формулы Соловьёва, Иванова, Солнышкиной 2023 года, значения которого в статье лежат в пределах 200-1000 (sis_grade_by_freq).

Редкие слова опускают покрытие и логарифм частотности и поднимают сюрпризал и долю вне топ-10000:

from ruts import LexicalStats

ls = LexicalStats("Фелинолог пребывал на подоконнике")
ls.coverage, ls.mean_log_ipm, ls.surprisal, ls.p_beyond_top10000
(0.75, 2.3063585317426494, 14.515882690436708, 0.25)

Сюрпризал и перплексия

surprisal · perplexity

calc_surprisal(lemmas, freq_dict)

Средний сюрпризал слов по униграммной модели частотного словаря в битах; слово вне словаря получает его наименьшую частоту min_ipm. Перплексия - 2 в его степени.

\[ \frac{1}{N} \sum_{w} -\log_2 \frac{\max(\textrm{ipm}_w, \textrm{min\_ipm})}{10^6} \]
Параметр Тип По умолчанию Описание
lemmas list[str] - Ключи слов в словаре
freq_dict FrequencyDictionary - Частотный словарь

Без слов результат - nan; ключи, которые не список строк, и словарь без ipm и min_ipm дают SourceTypeError, наименьшая частота не больше нуля - ParameterError.

В ruTS словарь - FreqDict с наименьшей частотой 0.4 ipm: словарь другого класса дает SourceTypeError.

from ruts.datasets import FreqDict
from ruts.lexical_stats import calc_surprisal

calc_surprisal(["кот", "сидеть", "фелинолог"], FreqDict())
15.570731790883956

Частотные полосы

p_top1000 · p_top2000 · p_top5000 · p_top10000 · p_beyond_top10000 · band_coverage(bands, unique)

Доля слов, лемма которых имеет ранг (rank) в пределах топ-\(N\) списка, для границ 1000, 2000, 5000 и 10000 из FREQUENCY_BANDS; доля вне топ-10000 - остаток, включая слова вне списка. Полоса больше размера списка (top_size) равна nan, как и доля вне топ-10000 для списка короче 10000.

\[ \frac{\textrm{Количество слов с рангом до } N}{\textrm{Количество слов}} \]

Так строится профиль частотных полос по образцу Lexical Frequency Profile.

get_rank(lemma)

Ранг леммы по вшитому списку Шарова, None для леммы вне списка; лемма берется в любом регистре, с ё или без.

Параметр Тип По умолчанию Описание
lemma str - Лемма
load_top_lemmas()

Весь список из файла ruts/resources/sharoff_top10000.txt: ранг каждой леммы в нижнем регистре без буквы ё, начиная с 1; у дублей остается меньший ранг.

from ruts.lexical_stats import get_rank, load_top_lemmas

get_rank("и"), get_rank("кот"), get_rank("фелинолог")
len(load_top_lemmas())
(1, 2009, None)
9989

Лексическая плотность

lexical_density

Доля знаменательных слов (существительные, прилагательные, глаголы, наречия без местоименных и вводных слов) среди всех слов; знаменательное слово определяет is_content_word для строки и CONTENT_UD_POS для Doc с разметкой.

\[ \frac{\textrm{Количество знаменательных слов}}{\textrm{Количество слов}} \]

Методы

band_coverage(bands, unique) возвращает долю слов с леммой из топ-N списка для каждой границы N из bands (по умолчанию FREQUENCY_BANDS), а с unique=True - долю различных лемм. Границы, которые не список целых чисел, и граница вне промежутка от 1 до top_size() дают ParameterError.

from ruts import LexicalStats

ls = LexicalStats("Кот сидел на окне и смотрел на птиц")
ls.band_coverage(unique=True)
ls.band_coverage(bands=(100, 500))
{1000: 0.7142857142857143, 2000: 0.8571428571428571, 5000: 1.0, 10000: 1.0}
{100: 0.375, 500: 0.75}

Остальные методы - get_stats, to_dataframe, print_stats и describe - из интерфейса статистик ядра anyTS; шкал у статистик лексической сложности нет, поэтому describe для статистик get_stats возвращает None.

ls.get_stats()
{'coverage': 1.0,
 'mean_ipm': 8645.5375,
 'mean_ipm_content': 324.18,
 'mean_log_ipm': 3.0674194359404705,
 'mean_log_ipm_content': 2.316850597556863,
 'mean_range': 99.75,
 'mean_dispersion': 95.125,
 'surprisal': 9.74182176626998,
 'perplexity': 856.2105288389297,
 'p_top1000': 0.75,
 'p_top2000': 0.875,
 'p_top5000': 1.0,
 'p_top10000': 1.0,
 'p_beyond_top10000': 0.0,
 'lexical_density': 0.625}