Files
NLP/lab1/RESULTS_ANALYSIS.md

386 lines
24 KiB
Markdown
Raw 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.

# Анализ результатов follow-up серии
Дата анализа: 26.10.2026.
Источник результатов:
- ветка `origin/opencode_test`, коммит `ac7c6f0`;
- основной архив `lab1/exports/nlp_lab1_results_20261026_054117.tar.gz`;
- сводки `results/followup/summary.csv`, `summary.md`, `comparisons.csv`,
`comparisons.md`;
- документ коллеги `FOLLOWUP_EXPERIMENTS.md`.
Контрольные суммы архивов совпали. В основном архиве — 68 запусков; ключевые
конфигурации выполнены с 5 повторами 5-блочной стратифицированной
перекрёстной проверки, seed 42. Дополнительно есть nested-запуски, контроли
перестановкой меток, анализ почти-дублей, длины реплик и подгрупп.
Настоящий документ — независимая сводка: что можно утверждать, что нельзя,
и какие эксперименты нужны дальше.
---
## 1. Краткий ответ
1. **Персонажей можно различать, но сигнал умеренный.** Лучшая конфигурация
даёт macro-F1 около **0,258** при случайном уровне **0,029**; top-3 —
около **0,42** при случайном **0,088**. Это в 7–9 раз выше случайного
уровня, но не «почти безошибочная» классификация.
2. **Основной сигнал — лексико-тематический, а не чисто стилистический.**
Ручные стилометрические признаки дают 0,105; добавление символьных и
частеречных n-грамм поднимает до 0,182; `content`-LSA — до 0,248–0,258.
Функциональные слова и POS-LSA сами по себе слабы (0,06–0,07).
3. **Лучшие кандидаты — `char_max10000_rf` и `model_et_default`.** Они
статистически неразличимы: +0,0031, 3/5 повторов, p = 0,57,
доверительный интервал накрывает ноль. `groups_lean2_content300` тоже
близок (0,251), но опирается на `content`-LSA, то есть скорее на тему.
4. **`final_rf` — не лучшая модель.** Дефолтный random forest даёт 0,222,
тогда как ExtraTrees — 0,255, а RF с `char_max_features=10000` — 0,258.
В отчёте `final_rf` нужно переименовать в `baseline_rf` или заменить.
5. **Ошибки — это коллапс в «hub»-классы, а не демографическая путаница.**
Abigail получает 21–23% всех предсказаний при истинной доле 6,9%;
precision 0,087, recall 0,266. Редкие классы (Kent, Wizard, Penny,
Mister Qi) почти не находятся.
6. **Строгий вывод о стиле пока невозможен.** `content`-LSA и широкие
символьные n-граммы могут кодировать содержание и тему. Нужен
тематический контроль и внешняя валидация.
---
## 2. Ранжирование моделей
`Δ` — разница с `ref_logreg` (0,1785). Для nested-запусков указан один
внешний цикл из 5 блоков, поэтому std по повторам равен нулю.
| Label | Модель | Повторов | Macro-F1 | Δ | Accuracy | Top-3 |
|---|---|---:|---:|---:|---:|---:|
| `char_max10000_rf` | random forest | 5 | **0,2583 ± 0,0066** | +0,0798 | 0,2391 | 0,4197 |
| `char_max10000_rf_nested` | random forest, nested | 1×5 | **0,2579** | +0,0794 | 0,2394 | 0,4075 |
| `groups_lean2_content300_nested` | logreg, nested | 1×5 | **0,2572** | +0,0788 | 0,2369 | 0,4065 |
| `model_et_default` | extra trees | 5 | **0,2551 ± 0,0073** | +0,0767 | 0,2387 | 0,4170 |
| `et_dNone_l2` | extra trees | 3 | 0,2538 ± 0,0089 | +0,0753 | 0,2416 | 0,4308 |
| `groups_lean2_content300` | logreg | 5 | 0,2510 ± 0,0040 | +0,0725 | 0,2379 | 0,4111 |
| `model_et_nested` | extra trees, nested | 1×5 | 0,2486 | +0,0701 | 0,2344 | 0,4259 |
| `stylometry_pos_content300` | logreg | 5 | 0,2485 ± 0,0042 | +0,0700 | 0,2337 | 0,4175 |
| `rf_grid_best_5` | random forest | 5 | 0,2294 ± 0,0082 | +0,0509 | 0,2253 | 0,4004 |
| `model_rf_default` | random forest | 5 | 0,2213 ± 0,0065 | +0,0428 | 0,2108 | 0,3893 |
| `final_rf` | random forest, 10 повторов | 10 | 0,2216 ± 0,0062 | +0,0431 | 0,2094 | 0,3865 |
| `model_svc_default` | linear SVC | 5 | 0,1880 ± 0,0067 | +0,0096 | 0,1840 | 0,3386 |
| `ref_no_lsa` | logreg, `stylometry_pos` | 5 | 0,1815 ± 0,0054 | +0,0031 | 0,1708 | 0,3395 |
| `ref_logreg` | logreg, `stylometry_pos_lsa` | 5 | 0,1785 ± 0,0060 | 0 | 0,1679 | 0,3322 |
| `stylometry` | logreg, только ручные признаки | 5 | 0,1051 ± 0,0038 | −0,0733 | 0,1012 | 0,2338 |
| `lsa_content_k400` | logreg, только content-LSA | 5 | 0,2114 ± 0,0029 | +0,0329 | 0,2059 | 0,3767 |
| `lsa_pos_k300` | logreg, только POS-LSA | 5 | 0,0667 ± 0,0040 | −0,1118 | 0,0663 | 0,1556 |
| `control_length_logreg` | logreg, только длина | 5 | 0,0354 ± 0,0032 | −0,1430 | 0,0395 | 0,1345 |
| `control_length_dummy` | dummy | 1 | 0,0038 | −0,1747 | 0,0693 | 0,1022 |
Случайный уровень: macro-F1 ≈ 0,029, accuracy ≈ 0,029, top-3 ≈ 0,088.
Контроль перестановкой меток дал 0,0270–0,0282, то есть ровно случайный
уровень. Признаков утечки через метки не видно.
---
## 3. Статистическая надёжность
Главные парные сравнения:
| Сравнение | Δ macro-F1 | Повторов в плюс | McNemar p | Bootstrap CI |
|---|---:|---:|---:|---:|
| `char_max10000_rf` vs `ref_logreg` | +0,0798 | 5/5 | < 0,0001 | [+0,053, +0,099] |
| `model_et_default` vs `ref_logreg` | +0,0767 | 5/5 | < 0,0001 | [+0,054, +0,099] |
| `groups_lean2_content300` vs `ref_logreg` | +0,0725 | 5/5 | < 0,0001 | [+0,053, +0,092] |
| `stylometry_pos_content300` vs `ref_no_lsa` | +0,0669 | 5/5 | < 0,0001 | [+0,050, +0,083] |
| `char_max10000_rf` vs `model_rf_default` | +0,0369 | 5/5 | 0,0032 | [+0,020, +0,053] |
| `model_et_default` vs `model_rf_default` | +0,0338 | 5/5 | 0,0113 | [+0,018, +0,050] |
| `char_max10000_rf` vs `model_et_default` | +0,0031 | 3/5 | 0,5732 | [−0,014, +0,021] |
| `char_max10000_rf` vs `groups_lean2_content300` | +0,0073 | 5/5 | 0,6593 | [−0,017, +0,030] |
Выводы:
- преимущество деревьев над логистической регрессией устойчиво и велико;
- ExtraTrees устойчиво лучше дефолтного random forest;
- `char_max10000_rf`, ExtraTrees и `groups_lean2_content300` между собой
статистически неразличимы;
- малые различия (+0,003…+0,009) не переживают множественную поправку и
не должны трактоваться как выигрыш.
Для 46 парных сравнений нужна поправка Холма—Бонферрони. Эффекты
+0,04…+0,08 с p < 0,001 её переживут; пограничные +0,003…+0,009 — нет.
---
## 4. Что именно даёт качество
| Компонент | Macro-F1 | Интерпретация |
|---|---:|---|
| Только длина | 0,035 | Слабая нижняя граница |
| Только ручные стилометрические признаки | 0,105 | Стиль/структура без лексических n-грамм |
| Ручные + char/POS n-граммы | 0,1815 | Основной прирост +0,077 |
| То же + word/pos-LSA(k=100) | 0,1785 | LSA по умолчанию не помогает |
| То же + content-LSA(k=300) | 0,2485 | Сильный прирост, но это тема/лексика |
| Только content-LSA(k=400) | 0,2114 | Контент сам по себе сильнее ручной стилометрии |
| Только POS-LSA(k=300) | 0,0667 | Синтаксис в таком виде слаб |
| Только функциональные слова | 0,0598 | Стиль без лексики слаб |
| RF + char_max_features=10000 | 0,2583 | Лучший результат |
Это главный содержательный вывод: **модель различает персонажей в первую
очередь по лексико-тематическому профилю и символьным n-граммам**, а не по
«чистому» синтаксису или функциональным словам. Формулировка «модель выучила
идиолект» слишком сильная. Корректнее: «модель различает персонажей по
устойчивым лексическим и тематическим маркерам, которые автор закрепил за
речевыми масками».
Дополнительное подтверждение: lean-набор без `function_words`, `pos`,
`vocabulary` и `readability` даёт 0,1808, то есть **не хуже** полного
`stylometry_pos_lsa` (0,1785). Удаление «стилевых» групп не ухудшает
результат, потому что основной сигнал несут char- n-граммы и лексика.
---
## 5. LSA: тема или стиль
Зависимость от числа компонент для `content`-LSA монотонная:
| k | Macro-F1 |
|---:|---:|
| 100 | 0,1334 |
| 200 | 0,1796 |
| 300 | 0,1984 |
| 400 | 0,2128 |
Для сравнения: `word` при k=400 — 0,1781, `char` при k=400 — 0,1787,
`pos` — около 0,071, `fw` — около 0,074.
Интерпретация:
- `content`-LSA строится по содержательным словам и их биграммам; это
кодирует **о чём говорит персонаж**, а не только **как**;
- сильный рост при k=300–400 означает, что тематическая вариативность
богата и хорошо разделяет персонажей;
- `word+pos` LSA при k=100 была нейтральна, но это не значит, что «LSA
вообще не работает»: важен вариант и число компонент;
- POS-LSA при добавлении к полному набору **ухудшает** результат
(`stylometry_pos_pos300` = 0,1685 против 0,1815), то есть синтаксический
LSA в текущем виде шумит.
Пока нет тематического контроля, прирост `content`-LSA нельзя записывать в
стилометрию. Нужны: сбалансированные по темам подвыборки, удаление
тематических слов или adversarial-контроль темы.
---
## 6. Ошибки модели
Для лучшей модели `char_max10000_rf` (таблицы `per_class_report.csv` и
`confusion_matrix.csv` относятся к repeat 0; доли предсказаний проверены по
всем пяти повторам):
- Abigail получает **21–23%** всех предсказаний при истинной доле **6,9%**;
precision 0,087, recall 0,266, F1 0,131.
- Alex получает 11–12% при истинной доле 6,0%.
- Худшие F1: Kent 0,000, Wizard 0,048, Penny 0,050, Mister Qi 0,069,
Leah 0,083, Jodi 0,098, Linus 0,105.
- Лучшие F1: Evelyn 0,645, Willy 0,578, Pam 0,534, Pierre 0,518,
Leo 0,440, Vincent 0,393, Krobus 0,392.
- Крупнейшие потоки ошибок: Sebastian → Abigail (40), Haley → Abigail (31),
Alex → Abigail (28), Penny → Abigail (27), Sam → Abigail (25).
- Это **hub-коллапс**: редкие и средние классы стягиваются в несколько
популярных, а не путаются по возрасту или полу.
`groups_lean2_content300` ведёт себя иначе: Abigail получает только 3,6%
предсказаний, а Wizard F1 = 0,449. Ошибки моделей комплементарны, поэтому
ансамбль может быть полезен.
### 6.1. Длина реплики
Для `char_max10000_rf`, repeat 0:
| Длина | Macro-F1 | Доверительный интервал |
|---|---:|---:|
| 0–5 слов | 0,088 | [0,033; 0,122] |
| 6–10 | 0,218 | [0,153; 0,258] |
| 11–15 | 0,222 | [0,170; 0,258] |
| 16–20 | 0,239 | [0,190; 0,271] |
| 21–30 | **0,285** | [0,238; 0,315] |
| 31+ | 0,240 | [0,180; 0,273] |
Зависимость немонотонная: после 30 слов качество падает. Гипотеза «чем
длиннее, тем лучше» не подтверждается; длинные реплики накапливают
тематические и синтаксические различия.
### 6.2. Подгруппы
Для `char_max10000_rf`, repeat 0:
- возраст: elder 0,406, child 0,378, adult 0,232, teen 0,196;
- пол: male 0,266, unknown 0,244, female 0,218;
- вид: monster 0,295, human 0,246, unknown 0,056.
Это F1 **внутри группы персонажей**, а не качество предсказания группы.
Различия описательные; они не доказывают, что модель обязана путать
персонажей внутри группы.
### 6.3. Верификация и кластеризация
- Верификация: ROC-AUC 0,630–0,633, EER 0,412–0,415, TAR@FAR=1% 0,035–0,038,
top-1 0,133–0,141. Выше случайного, но практически слабо.
- Кластеризация: ARI = 0 для k = 3/5/8, NMI 0,14–0,53. Устойчивых кластеров
персонажей в этом пространстве нет.
---
## 7. Ансамбль: предварительный результат
По out-of-fold предсказаниям (одинаковые повторы и seed) я проверил простое
голосование:
| Комбинация | Macro-F1 |
|---|---:|
| `char_max10000_rf` + `model_et_default` | 0,2583 |
| + `groups_lean2_content300` | **0,2728 ± 0,0024** |
| + `stylometry_pos_content300` | 0,2751 ± 0,0036 |
Это **не** валидная финальная модель: голосование построено постфактум по
тем же OOF-предсказаниям, которые использовались для выбора конфигураций.
Но результат показывает, что ошибки моделей комплементарны и что
`VotingClassifier`/stacking — перспективное направление. Проверять его нужно
в отдельном nested-эксперименте, а не по этим числам.
---
## 8. Методологические ограничения
1. **Выбор признаков на тех же данных.** `char_max_features=10000`,
`content`-LSA(k=300/400) и lean-наборы выбирались по результатам на
тестовых фолдах. Nested CV в текущем виде настраивает только `C`,
`max_depth` и `min_samples_leaf`; выбор признаков остаётся снаружи.
Поэтому 0,258 может быть оптимистичной оценкой. Нужен внешний holdout или
nested-выбор признаков.
2. **Множественные сравнения.** 46 пар; мелкие эффекты не переживают
поправку Холма—Бонферрони.
3. **Один корпус.** Все 2005 реплик — из одной игры; внешней валидации нет.
Разбиение по репликам не учитывает сцены и диалоги.
4. **Один автор.** Это классификация речевых масок, а не авторская
атрибуция.
5. **Короткие тексты и дисбаланс.** 15–139 реплик на класс; редкие классы
имеют широкие интервалы, а hub-классы забирают предсказания.
6. **Тематический конфликт.** `content`-LSA и char- n-граммы могут кодировать
тему, сезоны, подарки, работу и имена. Без контроля темы нельзя утверждать,
что модель выучила стиль.
7. **McNemar и macro-F1 не всегда согласованы.** Например, отключение
`class_weight` у logreg снижает macro-F1 на 0,029, но McNemar даёт
p = 0,65, потому что общая accuracy почти не меняется. Для выводов о
macro-F1 нужны повторные разницы и bootstrap, а не только McNemar.
8. **`final_rf` — не финальная модель.** Это дефолтный RF с 0,222; он
проигрывает ET и char-RF.
---
## 9. Выводы
1. **Гипотеза о различимости персонажей подтверждается частично.**
Лучшая модель: macro-F1 ≈ 0,258, top-3 ≈ 0,42, accuracy ≈ 0,239 при
34 классах. Это заметно выше случайного уровня, но далеко от надёжной
практической классификации.
2. **Основной вклад дают лексика, символьные n-граммы и content-LSA.**
Ручные стилометрические признаки и POS/функциональные слова сами по себе
слабы. Поэтому результат нельзя интерпретировать как «чистый идиолект».
3. **Лучшие модели — ExtraTrees и RF с расширенным char-словарём.**
Они статистически неразличимы. ET проще и не требует выбора
`char_max_features`; char-RF даёт максимум, но его конфигурация выбрана
на тех же данных.
4. **`content`-LSA — сильный, но тематический сигнал.** Он улучшает
результат, однако требует тематического контроля; POS-LSA в текущем виде
вредит.
5. **Главная проблема — не seed, а hub-коллапс и редкие классы.**
Abigail, Alex и ещё несколько классов забирают чужие предсказания.
Калибровка prior/порогов и работа с редкими классами перспективнее
дальнейшего перебора глубины деревьев.
6. **Ансамбль моделей перспективен, но пока не проверен корректно.**
Предварительное голосование даёт 0,273; нужен отдельный nested-эксперимент.
7. **Для строгого вывода о стиле нужны внешняя валидация и тематический
контроль.** Без них корректная формулировка: «персонажи различимы по
лексико-тематическому профилю и символьным n-граммам».
---
## 10. Что делать дальше
### Приоритет 0 — честная финальная оценка
1. Выбрать одну финальную модель: `model_et_default` (проще) или
`char_max10000_rf` (максимум).
2. Провести nested CV, в котором внутри внешнего цикла выбираются не только
гиперпараметры, но и `char_max_features`, `min_df`, `ngram_range` и
`content`-LSA(k).
3. Либо зафиксировать конфигурацию до анализа и проверить на отдельном
holdout/новом корпусе.
4. Заменить `final_rf` на реального лидера или переименовать его в
`baseline_rf`.
### Приоритет 1 — тематический контроль
- сбалансировать реплики по темам/сезонам;
- удалить тематические слова и проверить падение `content`-LSA;
- обучить классификатор темы и проверить, не объясняет ли она результат;
- сравнить `content`-LSA с `pos`/`fw` на тематически однородных подвыборках.
### Приоритет 2 — ошибки и калибровка
- prior correction / temperature scaling для hub-классов;
- пороги на OOF, оптимизирующие macro-F1, а не только accuracy;
- анализ `Abigail`, `Alex`, `Kent`, `Wizard`, `Penny`;
- отдельный отчёт по редким классам.
### Приоритет 3 — ансамбли и признаки
- `VotingClassifier`/stacking по OOF-вероятностям;
- `content`-LSA k=400/500 с lean-набором;
- char `max_features` 10000–15000, `min_df` 2–3;
- block weights;
- внешняя валидация на другом корпусе или разбиении по сценам.
---
## 11. Артефакты
```text
lab1/exports/nlp_lab1_results_20261026_054117.tar.gz
lab1/FOLLOWUP_EXPERIMENTS.md
lab1/scripts/analyze_followup.py
lab1/scripts/run_followup_experiments.sh
```
После распаковки архива:
```text
results/followup/summary.csv
results/followup/summary.md
results/followup/comparisons.csv
results/followup/comparisons.md
results/followup/<label>/
```
Команда для повторного анализа:
```bash
python scripts/analyze_followup.py \
--followup-dir results/followup \
--pairs char_max10000_rf:ref_logreg \
char_max10000_rf:model_et_default \
groups_lean2_content300:ref_logreg
```
---
## 12. Итоговая формулировка для отчёта
> Персонажи Stardew Valley статистически различимы по отдельным репликам:
> лучшая модель достигает macro-F1 ≈ 0,26 и top-3 ≈ 0,42 при 34 классах
> (случайный уровень 0,029 и 0,088 соответственно). Однако основной вклад
> дают лексико-тематические признаки и символьные n-граммы, а не
> функциональные слова и синтаксис. Поэтому результат корректно
> интерпретировать как различимость речевых масок по лексико-тематическому
> профилю; для утверждения о «чистом стиле» необходимы тематический контроль
> и внешняя валидация.