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