47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
"""Относительные частоты функциональных слов.
|
|
|
|
Это ядро классической стилометрии: закрытые классы слов мало зависят от
|
|
темы, но хорошо отражают авторский или персонажный синтаксис.
|
|
"""
|
|
|
|
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()
|