"""Относительные частоты функциональных слов. Это ядро классической стилометрии: закрытые классы слов мало зависят от темы, но хорошо отражают авторский или персонажный синтаксис. """ from __future__ import annotations import re import pandas as pd from ..lexicons import FUNCTION_WORD_CATEGORIES, FUNCTION_WORDS from .base import as_list, safe_div, word_tokens def _safe_name(word: str) -> str: return re.sub(r"[^a-z0-9]+", "_", word.lower()).strip("_") def _sorted_words() -> list[str]: return sorted(FUNCTION_WORDS) def extract(row: pd.Series) -> dict[str, float]: tokens = [token.lower() for token in word_tokens(as_list(row, "tokens"))] n_words = max(len(tokens), 1) features: dict[str, float] = {} for word in _sorted_words(): features[f"fw_word_{_safe_name(word)}"] = safe_div(tokens.count(word), n_words) for category, vocabulary in FUNCTION_WORD_CATEGORIES.items(): count = sum(1 for token in tokens if token in vocabulary) features[f"fw_cat_{category}"] = safe_div(count, n_words) features["fw_total_rate"] = safe_div( sum(1 for token in tokens if token in FUNCTION_WORDS), n_words ) features["fw_unique_types"] = float(len(set(tokens) & FUNCTION_WORDS)) return features def feature_words() -> list[str]: """Список слов, для которых создаются отдельные признаки.""" return _sorted_words()