@@ -0,0 +1,385 @@
# Анализ результатов 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-граммы, а не
> функциональные слова и синтаксис. Поэтому результат корректно
> интерпретировать как различимость речевых масок по лексико-тематическому
> профилю; для утверждения о «чистом стиле» необходимы тематический контроль
> и внешняя валидация.