Files
NLP/lab1/EXPERIMENTS.md

748 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Протокол экспериментов
Документ описывает постановку, признаки, схему валидации, метрики и порядок
запуска экспериментов. Он рассчитан на следующего исследователя, который будет
проводить финальные серии опытов и готовить отчёт.
Методические пояснения к метрикам и классификаторам вынесены в
`METRICS_AND_CLASSIFIERS.md`. Здесь — практическая часть: что запускать, в
каком порядке и как интерпретировать результаты.
---
## 1. Исследовательский вопрос
**Вопрос.** Различимы ли 34 персонажа Stardew Valley по стилометрическим
признакам отдельных реплик, если все реплики написаны одним автором?
Это задача **классификации речевых масок персонажей**, а не авторской
атрибуции. Автор один, но персонажи наделены разной лексикой, синтаксисом,
междометиями, длиной реплик и пунктуацией. Положительный результат означает,
что созданные автором речевые маски статистически различимы; он не означает,
что у персонажей разные авторы.
### Гипотезы
| Обозначение | Гипотеза | Как проверяем |
|---|---|---|
| H1 | Функциональные слова, POS-признаки и символьные n-граммы различают персонажей выше случайного уровня | E2, E3, E4 |
| H2 | На коротких репликах POS- и char-признаки устойчивее словарного богатства и читаемости | E3, E9 |
| H3 | LSA по всем словам отражает тему, а LSA по POS и функциональным словам — стиль | E7 |
| H4 | Более длинные реплики классифицируются лучше | E9 |
| H5 | Ошибки группируются вокруг персонажей со сходным возрастом, полом, ролью или «человечностью» | E14 |
Случайный уровень для 34 классов: доля правильных ответов около 2,9%,
macro-F1 около 2,9%, top-3 около 8,8%. Любые результаты нужно сравнивать с
этими значениями, а не с нулём.
---
## 2. Данные
### 2.1. Текущий корпус
| Параметр | Значение |
|---|---|
| Файл | `data/dialogues.csv` |
| Кодировка | cp1251 |
| Реплик | 2005 |
| Персонажей | 34 |
| Словоупотреблений | около 38,2 тыс. |
| Средняя длина реплики | 19,1 слова |
| Медиана | 17 слов |
| Минимум / максимум | 3 / 78 слов |
| Классы | 15–139 реплик |
| Точные дубли реплик | 0 |
Корпус уже прошёл ручную фильтрацию: удалены короткие и общие фразы. Точные
правила очистки не сохранились, поэтому корпус используется как есть. Это
ограничение нужно указать в отчёте: восстановить исходное распределение
коротких реплик нельзя.
Редкие классы: Mister Qi (15), Sandy (21), Dwarf (23), Wizard (24),
Vincent (26), Krobus (28). При 5-блочной кросс-валидации у Mister Qi в каждом
тестовом блоке около 3 реплик; метрики по нему будут иметь широкий
доверительный интервал.
### 2.2. Аудит
```bash
cd lab1
python -m stylometry.cli audit
```
Результаты:
- `data/processed/lines.csv` — нормализованные реплики;
- `data/processed/audit.md` — отчёт с распределением классов, длин и сверкой
с `stats_per_character.xlsx`;
- `data/processed/figures/class_distribution.png` — график.
---
## 3. Предобработка
Корпус не перечищается. Выполняются только обратимые и не меняющие смысл
операции:
1. Приведение Unicode: многоточие, кавычки, тире, неразрывные пробелы.
2. Замена плейсхолдеров `<PLAYER>`, `<FARM>`, `<PET>`, `<SPOUSE>`, `<TIME>`,
`<NOUN>`, `<NAME>` на слова `PLAYER`, `FARM` и т.д. Количество плейсхолдеров
сохраняется отдельным признаком.
3. Схлопывание повторных пробелов.
4. Токенизация NLTK: `word_tokenize`.
5. Разбиение на предложения: `sent_tokenize`.
6. Частеречная разметка: `pos_tag`; перевод тегов Penn Treebank в Universal
POS.
7. Для POS-последовательностей подряд идущие знаки препинания схлопываются в
один тег `PUNCT`.
Не выполняется:
- удаление стоп-слов (они являются стилометрическим сигналом);
- удаление пунктуации;
- лемматизация по умолчанию (инфлексия — тоже стиль);
- удаление коротких реплик;
- приведение регистра к нижнему для всех признаков.
### 3.1. Ресурсы NLTK
```bash
cd lab1
python scripts/download_nltk_data.py
```
Скачиваются `punkt`, `punkt_tab`, `averaged_perceptron_tagger`,
`averaged_perceptron_tagger_eng`, `stopwords` в `lab1/nltk_data`. Если ресурсы
недоступны, токенизатор переходит в резервный режим на регулярных выражениях,
а POS-признаки отключаются. Для финальных экспериментов нужен NLTK-режим:
проверьте, что в метаданных запуска `pos_available=true`.
---
## 4. Признаковое пространство
### 4.1. Ручные стилометрические признаки
Всего около 454 признаков. Они не обучаются на данных, поэтому могут быть
посчитаны заранее.
| Группа | Примеры | Статус |
|---|---|---|
| Длина | число токенов, слов, символов, предложений; средняя длина предложения; доля длинных слов | Основная, но чувствительна к длине |
| Лексика | распределение длин слов, доля слов с апострофом, заглавных, цифр | Основная |
| Словарное богатство | TTR, Guiraud, Herdan, Yule's K, Simpson's D, hapax/dis, Honoré | Предварительный |
| Символы | частоты букв a–z, доля заглавных, цифр, пунктуации, апострофов | Основная |
| Пунктуация | запятые, точки, восклицательные, вопросительные, многоточия, повторная пунктуация | Основная |
| Функциональные слова | около 150 закрытых слов и 12 категорий | Основная |
| Местоимения | 1-е, 2-е, 3-е лицо, возвратные, притяжательные, отношение I/you | Основная |
| Части речи | Universal POS, Penn Treebank, модальность, время, герундий, причастие | Основная |
| Синтаксис-прокси | число клауз, подчинительные союзы, вопрос/восклицание, пассив-прокси | Основная |
| Читаемость | Flesch, FK grade, Gunning Fog, SMOG, Coleman-Liau, ARI | Предварительный |
| Разговорные маркеры | плейсхолдеры, ALL CAPS, многоточия, междометия, смех, дискурсивные маркеры, хеджи, интенсификаторы, вежливость, отрицания, сокращения | Основная |
Признаки `vocabulary` и `readability` помечены как предварительные: на репликах
длиной 10–20 слов они нестабильны. Их влияние нужно проверять отдельно, а не
включать в основной вывод без оговорок.
### 4.2. Символьные n-граммы
TF-IDF по `char_wb`, диапазон 2–5, `min_df=3`, до 5000 признаков, L2-норма.
Хорошо отражают морфологию, пунктуацию и орфографические привычки.
### 4.3. POS n-граммы
TF-IDF по последовательностям Universal POS, диапазон 1–3, `min_df=3`, до 500
признаков, L2-норма. Это относительно устойчивый к теме синтаксический сигнал.
### 4.4. Словарь признаков
```bash
python -m stylometry.cli features
```
Создаёт:
- `features/stylometric.csv` — матрица 2005 × 454;
- `features/feature_dictionary.csv` — название, группа, описание, статус.
Словарь нужно использовать в отчёте: для каждой группы указать, какие
признаки и почему выбраны.
---
## 5. Латентно-семантический анализ
LSA реализован как:
```text
TF-IDF -> TruncatedSVD(k) -> L2-нормализация
```
Варианты:
| Вариант | Колонка | n-граммы | Что отражает |
|---|---|---|---|
| `word` | `text` | 1 | тему и стиль |
| `word2` | `text` | 1–2 | тему и устойчивые сочетания |
| `content` | `content_text` | 1–2 | содержание после удаления стоп-слов |
| `fw` | `fw_text` | 1–2 | синтаксис через функциональные слова |
| `char` | `text` | 2–5 (символы) | морфологию и пунктуацию |
| `pos` | `pos_text` | 1–4 (POS) | синтаксический стиль |
Основные параметры: `sublinear_tf=true`, `min_df=3`, `max_df=0.9`,
`max_features=2000–8000`, `n_components=50–300`. Все параметры настраиваются
только на обучающих блоках; для интерпретационных графиков можно обучить LSA
на всём корпусе, но это нельзя использовать для оценки качества.
### 5.1. Что проверять в LSA
1. **График объяснённой дисперсии и накопленная дисперсия.** Сколько
компонент объясняют основную часть дисперсии.
2. **Top-термины компонент.** Интерпретируемость осей: тема, эмоциональность,
формальность, длина.
3. **Внешняя оценка.** Macro-F1 классификатора при разных `k`.
4. **Сравнение вариантов.** Если `lsa_word` и `lsa_content` значительно лучше
`lsa_pos` и `lsa_fw`, классификация в существенной степени опирается на
тему, а не на стиль.
5. **Стабильность.** Bootstrap по репликам и углы между подпространствами
(опционально; при малом числе компонент полезно).
### 5.2. Команды
```bash
python -m stylometry.cli lsa --variant word --components 100
python -m stylometry.cli lsa --variant pos --components 50
python -m stylometry.cli lsa --variant char --components 50
python -m stylometry.cli lsa-sweep --variants word,content,fw,char,pos \
--components 50,100,200 --model logreg --repeats 1
```
Результаты: матрицы `features/lsa_<variant>_k<k>.csv`, наиболее
информативные термины компонент, объяснённая дисперсия, график объяснённой
дисперсии.
---
## 6. Классификаторы
В основном сравнении участвуют:
| Модель | Краткая характеристика | Вероятности |
|---|---|---|
| `dummy` | предсказывает самый частый класс | да |
| `multinomial_nb` | наивный байесовский классификатор для неотрицательных признаков | да |
| `logreg` | логистическая регрессия с L2 и балансировкой классов | да |
| `linear_svc` | линейный метод опорных векторов | нет, есть решающая функция |
| `random_forest` | случайный лес | да |
| `extra_trees` | сверхслучайные деревья | да |
| `knn` | k ближайших соседей с косинусным расстоянием | да |
Для MultinomialNB автоматически исключаются LSA-блоки (компоненты могут быть
отрицательными) и используется MinMax-масштабирование. Для остальных моделей
ручные признаки стандартизуются и L2-нормируются, а TF-IDF- и LSA-блоки уже
нормированы. Это нужно, чтобы блоки разной размерности не подавляли друг
друга.
Подробное описание моделей, их формул, гиперпараметров и ограничений — в
`METRICS_AND_CLASSIFIERS.md`.
### 6.1. Сетки гиперпараметров
| Модель | Параметры |
|---|---|
| `logreg` | `C ∈ {0.1, 1, 10}` |
| `linear_svc` | `C ∈ {0.1, 1, 10}` |
| `random_forest`, `extra_trees` | `max_depth ∈ {None, 30}`, `min_samples_leaf ∈ {1, 2}` |
| `multinomial_nb` | `alpha ∈ {0.1, 1, 3}` |
| `knn` | `n_neighbors ∈ {3, 5, 9}` |
Настройка выполняется внутри вложенной кросс-валидации. Для одиночного запуска
`run` без `--nested` гиперпараметры фиксированы значениями по умолчанию; это
быстрее, но для финального сравнения нужен `--nested`.
---
## 7. Схема валидации
### 7.1. Основная схема
```python
RepeatedStratifiedKFold(n_splits=5, n_repeats=5, random_state=42)
```
Почему 5 блоков:
- минимальный класс — 15 реплик;
- в каждом тестовом блоке около 3 реплик на класс;
- все 34 класса присутствуют и в обучении, и в тесте;
- 10 блоков дали бы 1–2 реплики на класс и ещё более шумные оценки.
Почему повторная:
- один прогон 5-блочной CV даёт одну оценку; повторность позволяет оценить
разброс;
- для финального отчёта используйте 5 повторов; для быстрых проверок — 1–3.
### 7.2. Вложенная кросс-валидация
```python
outer = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
inner = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)
```
Внешние блоки — оценка качества; внутренние — настройка гиперпараметров.
Такой протокол уменьшает оптимистическое смещение, которое возникает, если
настраивать гиперпараметры на тех же данных, где измеряется качество.
### 7.3. Контроль утечек
- TF-IDF, SVD, масштабирование и отбор признаков обучаются только на
обучающем блоке.
- Ручные признаки и POS-теги не используют метки; их можно считать заранее.
- Точных дублей реплик в корпусе нет, поэтому одна и та же реплика не может
попасть в обучение и тест.
- При появлении почти одинаковых реплик нужно проверить `StratifiedGroupKFold`
с группами по нормализованному тексту. В текущем корпусе точных дублей нет.
- Нельзя выбирать признаки или `k` LSA по тестовым метрикам. Все решения — по
внутренней кросс-валидации.
---
## 8. Метрики
Подробные определения, формулы и интерпретация — в
`METRICS_AND_CLASSIFIERS.md`. Кратко:
| Метрика | Роль |
|---|---|
| Macro-F1 | Основная метрика: каждый из 34 классов равноправен |
| Сбалансированная доля правильных ответов | Средняя полнота по классам; удобна для редких персонажей |
| Доля правильных ответов | Нужна для сравнения с литературой |
| MCC | Устойчив к дисбалансу, учитывает все клетки матрицы ошибок |
| Cohen's kappa | Согласие с поправкой на случай |
| Top-3, top-5 | Важны при 34 классах |
| Log loss, Brier | Качество вероятностей и калибровка |
| Точность, полнота и F-мера по классам | Показывают, какие персонажи проваливаются |
| Матрица ошибок | Анализ пар перепутывания |
Основной отчётный результат — **pooled out-of-fold macro-F1** с 95%
бутстрэп-интервалом и среднее ± стандартное отклонение по повторам. Среднее
macro-F1 по отдельным блокам тоже полезно, но на класс приходится около трёх
объектов, поэтому оно шумное.
### 8.1. Статистические сравнения
- **Мак-Немар** — парное сравнение двух моделей на одних и тех же тестовых
репликах.
- **Уилкоксон** — парное сравнение результатов по блокам; описательная
проверка стабильности.
- **Фридман** — сравнение трёх и более моделей.
- **Поправка Холма—Бонферрони** — при множественных сравнениях.
- **Бутстрэп-интервалы** — основной способ показать неопределённость.
Не сравнивайте модели только по доле правильных ответов: при дисбалансе и
34 классах она может вводить в заблуждение. Пример: модель, предсказывающая
только Abigail, имеет долю правильных ответов около 7%, но macro-F1 около
0,004.
---
## 9. Матрица экспериментов
Все команды выполняются из `lab1`. Перед серией полезно один раз выполнить
`audit` и `features`.
### E0. Аудит корпуса
```bash
python -m stylometry.cli audit
```
Что проверить: число реплик и классов, распределение длин, отсутствие дублей,
совпадение с `stats_per_character.xlsx`.
### E1. Базовые уровни
```bash
python -m stylometry.cli run --preset length --model logreg --repeats 5
python -m stylometry.cli run --preset char --model multinomial_nb --repeats 3
python -m stylometry.cli run --preset pos --model multinomial_nb --repeats 3
python -m stylometry.cli run --preset fw --model logreg --repeats 3
python -m stylometry.cli run --preset length --model dummy --repeats 1
```
Смысл: понять, сколько сигнала даёт только длина, только символьные n-граммы,
только POS, только функциональные слова и случайная/частотная базовая модель.
### E2. Классическая стилометрия
```bash
python -m stylometry.cli run --preset stylometry --model logreg --repeats 5
python -m stylometry.cli run --preset stylometry --model linear_svc --repeats 5
```
Проверяет H1 на ручных признаках без n-грамм и LSA.
### E3. Поочерёдное исключение групп признаков
```bash
python -m stylometry.cli ablate --preset stylometry_pos_lsa --model logreg --repeats 3
```
Для каждой группы признаков строится вариант «без этой группы». Результат —
`results/ablation_*/ablation.csv` с колонкой `delta_macro_f1`. Отрицательное
значение означает, что удаление группы ухудшило качество; положительное — что
группа мешала (возможно, из-за шума или переобучения).
### E4. POS-признаки
Сравните:
```bash
python -m stylometry.cli run --preset stylometry --model logreg --repeats 5
python -m stylometry.cli run --preset stylometry_pos --model logreg --repeats 5
```
Разница macro-F1 показывает вклад символьных и POS n-грамм.
### E5. LSA: варианты и число компонент
```bash
python -m stylometry.cli lsa-sweep \
--variants word,content,fw,char,pos \
--components 50,100,200 \
--model logreg --repeats 1
```
Затем лучшие `k` и варианты проверить с 5 повторами через `run`:
```bash
python -m stylometry.cli run --preset lsa_word --model logreg --repeats 5
```
Для `lsa_word` и `lsa_pos` число компонент задаётся в `FeatureConfig`; в
командной строке текущая версия использует значение из `presets`
(`lsa_components=100`). Если нужно другое `k`, используйте `lsa-sweep` или
измените `FeatureConfig` в сценарии.
### E6. Сравнение классификаторов
```bash
python -m stylometry.cli benchmark --preset stylometry_pos_lsa \
--models logreg,linear_svc,random_forest,multinomial_nb,knn \
--repeats 3
```
Результат: `results/benchmark_*/summary.csv`, отдельные каталоги по моделям.
### E7. Стиль или тема
Сравните LSA-варианты:
```bash
python -m stylometry.cli lsa-sweep \
--variants word,content,fw,char,pos \
--components 50,100,200 --model logreg --repeats 1
```
Ожидаемая интерпретация:
- `word` и `content` лучше — вклад темы велик;
- `pos` и `fw` сопоставимы — стиль/синтаксис достаточно информативны;
- `char` полезен для морфологии и пунктуации.
### E8. Объединение блоков
```bash
python -m stylometry.cli run --preset stylometry_pos_lsa --model logreg --repeats 5
python -m stylometry.cli run --preset all --model logreg --repeats 3
```
Сравните с E2 и E5. Если объединение не лучше лучшего отдельного блока,
проверьте веса блоков и размерности.
### E9. Влияние длины
1. Запустите `run --preset length`, `--preset stylometry`,
`--preset stylometry_pos_lsa`.
2. Для сохранённого запуска выполните:
```bash
python -m stylometry.cli length-report --run-dir results/<каталог_запуска>
```
Команда сама соединяет предсказания с `data/processed/lines.csv`, разбивает
реплики на группы 0–5, 6–10, 11–15, 16–20, 21–30, 31+ слов и считает
macro-F1 с бутстрэп-интервалом. В каждой группе macro-F1 считается по
классам, которые в ней присутствуют; поэтому сравнение групп с разным
набором персонажей нужно интерпретировать осторожно. Результат сохраняется
в `length_bins.csv` внутри каталога запуска.
Ожидание: качество может зависеть от длины, но монотонность не гарантирована.
В предварительном прогоне объединённого набора лучшие значения оказались
в группах 21–30 и 31+ слов, а группа 0–5 слов дала широкий интервал из-за
малого числа объектов. Если длина вносит существенный вклад, сравните
результаты с `--preset length` и без length-признаков (поочерёдное исключение
групп).
### E10. Дисбаланс классов
```bash
python -m stylometry.cli benchmark --preset stylometry_pos_lsa \
--models logreg,linear_svc,random_forest --repeats 3
```
Смотрите не только macro-F1, но и F-меру по классам, сбалансированную долю
правильных ответов и support. Сравните `class_weight="balanced"` (в коде
включено для logreg, SVM, RF) с
вариантом без балансировки: для этого нужно изменить `make_classifier` или
передать параметр.
### E11. Дельта Барроуза
```bash
python -m stylometry.cli delta --features 100,200,500 --metrics manhattan,cosine --repeats 3
```
Классическая стилометрическая базовая модель. Ожидается, что на коротких репликах
он уступает ML-моделям; важен как независимая проверка.
### E12. Верификация «свой/чужой»
```bash
python -m stylometry.cli verify --preset stylometry_pos_lsa
```
Для каждой тестовой реплики считается близость к центроидам всех персонажей.
Положительный класс — центроид своего персонажа, отрицательный — чужие.
Метрики: ROC-AUC, EER, TAR@FAR=1%, top-1. Это более мягкая
постановка, чем 34-классовая классификация.
### E13. Кластеризация
```bash
python -m stylometry.cli cluster --preset stylometry_pos_lsa
```
Строятся центроиды персонажей, иерархическая кластеризация и k-means.
Метрики: ARI, NMI, силуэт. Кластеризация носит предварительный характер: она показывает, какие
персонажи близки в признаковом пространстве, но не заменяет классификацию.
### E14. Анализ ошибок
После любого запуска откройте:
- `per_class_report.csv` — precision, recall, F1, support по персонажам;
- `confusion_matrix_normalized.csv` — доли перепутывания;
- `top_confusions.csv` — самые частые пары;
- `figures/confusion_matrix.png` — тепловая карта.
Что искать:
- персонажи с малым support и низким F1;
- пары с высокой взаимной ошибкой (например, дети, нелюди, персонажи с
похожей ролью);
- влияние длины: короткие реплики чаще путаются;
- признаки, важные для лучшей модели (коэффициенты логистической регрессии,
permutation importance для деревьев).
Для анализа по метаданным (пол, возраст, вид) используйте:
```bash
python -m stylometry.cli subgroup-report \
--run-dir results/<каталог_запуска> --group gender
python -m stylometry.cli subgroup-report \
--run-dir results/<каталог_запуска> --group age_group
python -m stylometry.cli subgroup-report \
--run-dir results/<каталог_запуска> --group species
```
Команда сохраняет `subgroup_<group>_metrics.csv` и
`subgroup_<group>_confusions.csv`. Метаданные лежат в
`data/metadata/characters.csv`; это экспертные пометки, а не часть корпуса,
поэтому они не используются как признаки классификатора.
### E15. Статистическое сравнение
Для двух лучших моделей:
```bash
python -m stylometry.cli compare \
--run-a results/<каталог_запуска_A> \
--run-b results/<каталог_запуска_B>
```
Команда соединяет out-of-fold предсказания по `line_id`, проверяет
совпадение истинных классов и считает точный критерий Мак-Немара и
бутстрэп-интервал разницы macro-F1. Результат сохраняется в
`comparison_with_other.json`. Для корректного парного сравнения запускайте
модели с одинаковыми `--folds` и `--seed`.
Для трёх и более моделей используйте `friedman_test` из
`stylometry/stats.py` по метрикам блоков и поправку Холма.
### E16. Вложенная кросс-валидация
```bash
python -m stylometry.cli run --preset stylometry_pos_lsa --model logreg --nested
python -m stylometry.cli run --preset stylometry_pos_lsa --model linear_svc --nested
```
Это финальная проверка с настройкой гиперпараметров. Сохраняются
`best_params.json` и метрики внешних блоков.
### E17. Дополнительно: агрегация в псевдодокументы
Основной протокол — уровень реплик. Если понадобится формально закрыть
требование «не менее 30 предложений на текст», можно реализовать отдельный
сценарий: склеить реплики одного персонажа в псевдодокументы по 30 предложений
и повторить E2–E9. Этот сценарий **не включён** в основной код, потому что
меняет единицу анализа и уменьшает число объектов. Его результаты следует
рассматривать как robustness check, а не как замену основного эксперимента.
---
## 10. Контроль утечек и воспроизводимости
Перед финальным запуском проверьте:
- [ ] `data/processed/tokenized.pkl` соответствует текущему SHA-256 корпуса.
- [ ] В метаданных запуска `pos_available=true`; POS-признаки не отключились.
- [ ] TF-IDF, SVD и масштабирование обучаются внутри блоков (это обеспечивает
`Pipeline`; не выносите их наружу).
- [ ] `k` LSA и гиперпараметры выбраны по внутренней CV, а не по тесту.
- [ ] В корпусе нет точных дублей; при появлении почти одинаковых реплик
используется группировка.
- [ ] Для финальных чисел выполнено не менее 3–5 повторов.
- [ ] Сохранены `run_metadata.json`, `fold_metrics.csv`, `pooled_metrics.csv`,
`oof_predictions.csv`, `confusion_matrix.csv`.
- [ ] Указаны версии библиотек и seed.
---
## 11. Текущие технические прогоны
Ниже — предварительные результаты одного повтора 5-блочной CV. Они нужны
только для проверки работоспособности конвейера и **не являются финальными**:
один повтор даёт широкий интервал, а гиперпараметры не настраивались.
| Набор признаков | Модель | Macro-F1 | Доля правильных ответов | Top-3 |
|---|---|---:|---:|---:|
| `stylometry` | logreg | 0,1002 | 0,0988 | 0,2389 |
| `stylometry_pos` | logreg | 0,1780 | 0,1681 | 0,3367 |
| `stylometry_pos_lsa` | logreg | 0,1802 | 0,1706 | 0,3387 |
| `lsa_word`, k=50 | logreg | 0,0618 | 0,0628 | 0,1835 |
| `lsa_pos`, k=50 | logreg | 0,0443 | 0,0459 | 0,1202 |
| `char` | multinomial_nb | 0,0280 | 0,0973 | 0,2464 |
Наблюдения:
- символьные и POS n-граммы дают основной прирост относительно ручных
признаков;
- LSA по словам и POS сама по себе слабее, но в объединении даёт небольшой
прирост;
- доля правильных ответов у `char + multinomial_nb` около 9,7%, но
сбалансированная доля правильных ответов 4,7% и macro-F1 2,8%: модель
предсказывает частые классы. Это иллюстрация того, почему долю правильных
ответов нельзя использовать как единственную метрику.
Верификация для `stylometry` (5 блоков): ROC-AUC ≈ 0,648, EER ≈ 0,395,
top-1 ≈ 0,093. Это выше случайного уровня (ROC-AUC 0,5), но далеко от
практически надёжного различения.
Поочерёдное исключение групп для `stylometry` (один повтор): удаление группы `characters`
снижает macro-F1 примерно на 0,015, удаление `vocabulary` — примерно на
0,008; остальные изменения в пределах шума. Эти числа нужно перепроверить с
несколькими повторами.
---
## 12. Как интерпретировать результаты
1. **Сравнивайте с случайным уровнем.** Для 34 классов доля правильных
ответов 2,9%, macro-F1 2,9%, top-3 8,8%.
2. **Основной вывод — по macro-F1 и доверительному интервалу**, а не по
доле правильных ответов.
3. **Смотрите F-меру по классам.** Если редкие персонажи не различаются, это
важный вывод, а не техническая деталь.
4. **Сравнивайте стиль и тему.** Если `lsa_word`/`lsa_content` значительно
лучше `lsa_pos`/`lsa_fw`, классификатор опирается на содержание.
5. **Проверяйте длину.** Если `length` даёт заметный сигнал, часть результата
объясняется длиной реплик, а не синтаксисом.
6. **Не переинтерпретируйте небольшие различия.** При 2005 объектах и 34
классах разница в 1–2 процентных пункта может быть шумом; нужны
доверительные интервалы и парные тесты.
7. **Помните про одного автора.** Результат говорит о различимости персонажей,
а не о разных авторах.
---
## 13. Ограничения
- Короткие тексты: признаки словарного богатства и читаемости нестабильны.
- Один автор: это классификация речевых масок, не авторская атрибуция.
- Ручная фильтрация корпуса: короткие и общие фразы удалены, правила не
восстановлены.
- Дисбаланс классов: 15–139 реплик; редкие классы дают широкие интервалы.
- Нет идентификаторов сцен: нельзя учесть корреляцию реплик внутри одной
сцены.
- NLTK-теггер ошибается на разговорных конструкциях.
- LSA может отражать тему; сравнение вариантов обязательно.
- Кластеризация и t-SNE — предварительный анализ, не доказательство.
---
## 14. Чек-лист перед защитой
- [ ] В отчёте описаны корпус, ручная фильтрация и её ограничения.
- [ ] Указано, что задача — character idiolect, а не авторская атрибуция.
- [ ] Перечислены группы признаков и обоснован выбор.
- [ ] Описаны варианты LSA и способ выбора числа компонент.
- [ ] Указаны классификаторы, гиперпараметры и схема валидации.
- [ ] Основная метрика — macro-F1; приведены доверительные интервалы.
- [ ] Есть отчёт по классам и матрица ошибок.
- [ ] Есть сравнение стиля и темы (`lsa_word` vs `lsa_pos`/`lsa_fw`).
- [ ] Есть анализ длины и поочерёдное исключение групп признаков.
- [ ] Есть статистическое сравнение моделей.
- [ ] Сформулированы ограничения и направления улучшения.
- [ ] Код, отчёт и презентация воспроизводимы по `README.md`.
---
## 15. Куда сохраняются результаты
```text
results/
├── <preset>_<model>_<timestamp>/
│ ├── run_metadata.json
│ ├── fold_metrics.csv
│ ├── fold_summary.csv
│ ├── pooled_metrics.csv
│ ├── bootstrap_ci.json
│ ├── oof_predictions.csv
│ ├── per_class_report.csv
│ ├── confusion_matrix.csv
│ ├── confusion_matrix_normalized.csv
│ ├── top_confusions.csv
│ ├── summary.md
│ └── figures/
├── benchmark_<preset>_<timestamp>/
│ ├── summary.csv
│ └── <model>/
├── ablation_<preset>_<timestamp>/
│ └── ablation.csv
├── lsa_sweep_<timestamp>/
│ └── lsa_sweep.csv
├── delta_<timestamp>/
│ └── delta_sweep.csv
├── verification_<preset>_<timestamp>/
│ ├── fold_metrics.csv
│ ├── pair_scores.csv
│ └── summary.json
└── clustering_<preset>_<timestamp>/
├── clustering_metrics.csv
├── character_centroids.csv
└── figures/
```