Многоклассовая классификация в атрибуции британских романов: опыт сравнительного анализа моделей
Данные
Материалом для работы послужил датасет корпуса A Small Collection of British Fiction (28 произведений британской прозы конца XVIII — XIX веков). Целью исследования было изучение стилистических особенностей авторов и классификация текстов по авторам методами машинного обучения.
Препроцессинг
Перед обучением моделей, тексты были разделены на чанки размером около 2000 слов (деление производилось по границам предложений). На графике представлен состав корпуса после сэмплинга.
Чанки были размечены при помощи пайплайна UDPipe. Затем из размеченных фрагментов (3220 наблюдений) были извлечены и сохранены леммы (за исключением имён собственных). Кроме того, удалось посчитать среднюю длину слов и предложений, а также долю различных частей речи и пунктуации в каждом из текстов. Сохранённые леммы затем использовались для создания списка наиболее частотных токенов и биграмм (по 2000 единиц), для которых была посчитана относительная частотность для каждого текста. Таким образом получилось собрать набор предикторов, состоящий из относительной частотности сущ., глаг., прил., наруч., имён собств., служ. слов и пунктуации, а также токенов и биграмм. Таблица ниже представляет собой полученные для обучения данные.
# A tibble: 3,220 × 4,011
author avg_word_len avg_sent_len function_words ADJ ADV NOUN PROPN
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Bronte,… 4.10 44.2 0.472 0.0669 0.0556 0.165 0.00859
2 Bronte,… 3.74 28.6 0.454 0.0627 0.0635 0.139 0.00639
3 Bronte,… 3.79 37.0 0.425 0.0714 0.0714 0.144 0.0151
4 Bronte,… 3.62 27.2 0.454 0.0469 0.0595 0.129 0.0198
5 Bronte,… 3.83 34.2 0.461 0.0541 0.0657 0.147 0.00945
6 Bronte,… 3.75 34.3 0.458 0.0578 0.0680 0.118 0.00971
7 Bronte,… 3.88 38.1 0.451 0.0564 0.0631 0.138 0.0102
8 Bronte,… 3.78 29.6 0.448 0.0511 0.0523 0.145 0.0169
9 Bronte,… 3.81 33.0 0.456 0.0558 0.0566 0.132 0.0156
10 Bronte,… 3.91 44.3 0.449 0.0767 0.0516 0.152 0.00980
# ℹ 3,210 more rows
# ℹ 4,003 more variables: PUNCT <dbl>, VERB <dbl>, a <dbl>, according <dbl>,
# action <dbl>, active <dbl>, admire <dbl>, advice <dbl>, affair <dbl>,
# affect <dbl>, affection <dbl>, after <dbl>, against <dbl>, air <dbl>,
# all <dbl>, along <dbl>, already <dbl>, always <dbl>, among <dbl>,
# amount <dbl>, amuse <dbl>, an <dbl>, and <dbl>, another <dbl>, any <dbl>,
# appeal <dbl>, argument <dbl>, as <dbl>, aspect <dbl>, assure <dbl>, …
Оценка релевантности предикторов
Частотность частей речи
Построим диаграммы частотности всех выделенных частей речи для каждого из произведений (цветом закодированы авторы). Из визуализаций хорошо видно, что столбики неизменно группируются по цветам, что говорит о том, что выбранные предикторы хорошо выполняют дискриминирующую функцию. По нашим наблюдениям, лучше всего работают частотности наречий, стоп-слов и имён собственных, однако сохраним все предикторы, так как каждый из них может играть роль при распознавании того или иного авторского сигнала.
Леммы и биграммы: эксперименты со снижением размерности
Также в качестве предикторов были выбраны частотные леммы и биграммы (по 2000 единиц в каждой категории). Такой объём предикторов для обучения избыточен, поэтому было принято решение снизить размерность матрицы лемм и матрицы биграмм при помощи различных методов (PCA, PLS и UMAP).
PCA
В рамках разведывательного анализа мы снизили размерность предикторов до 10-ти компонент.
# A tibble: 2,413 × 4,011
avg_word_len avg_sent_len function_words ADJ ADV NOUN PROPN
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.295 0.375 0.292 0.00394 -0.216 -0.629 -0.445
2 -0.978 -0.296 -0.811 0.712 0.117 -1.30 0.117
3 -2.03 0.524 -0.0709 -0.751 2.03 -2.34 0.0864
4 -0.447 0.0290 0.797 -1.20 1.92 -2.16 -0.932
5 -0.245 0.474 -0.759 0.979 -0.0432 -0.871 -0.843
6 -1.26 -0.443 -0.191 -0.0261 0.131 -1.19 -1.11
7 0.0283 0.0372 -0.320 -0.117 -0.526 0.299 -1.16
8 0.332 0.176 0.956 -0.383 0.261 -0.926 -0.647
9 -1.53 0.0328 1.24 -0.941 1.62 -2.41 -0.727
10 -0.672 0.594 0.563 0.636 2.54 -1.20 -1.58
# ℹ 2,403 more rows
# ℹ 4,004 more variables: PUNCT <dbl>, VERB <dbl>, a <dbl>, according <dbl>,
# action <dbl>, active <dbl>, admire <dbl>, advice <dbl>, affair <dbl>,
# affect <dbl>, affection <dbl>, after <dbl>, against <dbl>, air <dbl>,
# all <dbl>, along <dbl>, already <dbl>, always <dbl>, among <dbl>,
# amount <dbl>, amuse <dbl>, an <dbl>, and <dbl>, another <dbl>, any <dbl>,
# appeal <dbl>, argument <dbl>, as <dbl>, aspect <dbl>, assure <dbl>, …
# A tibble: 2,413 × 20
avg_word_len avg_sent_len function_words ADJ ADV NOUN PROPN
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.295 0.375 0.292 0.00394 -0.216 -0.629 -0.445
2 -0.978 -0.296 -0.811 0.712 0.117 -1.30 0.117
3 -2.03 0.524 -0.0709 -0.751 2.03 -2.34 0.0864
4 -0.447 0.0290 0.797 -1.20 1.92 -2.16 -0.932
5 -0.245 0.474 -0.759 0.979 -0.0432 -0.871 -0.843
6 -1.26 -0.443 -0.191 -0.0261 0.131 -1.19 -1.11
7 0.0283 0.0372 -0.320 -0.117 -0.526 0.299 -1.16
8 0.332 0.176 0.956 -0.383 0.261 -0.926 -0.647
9 -1.53 0.0328 1.24 -0.941 1.62 -2.41 -0.727
10 -0.672 0.594 0.563 0.636 2.54 -1.20 -1.58
# ℹ 2,403 more rows
# ℹ 13 more variables: PUNCT <dbl>, VERB <dbl>, author <fct>, PC01 <dbl>,
# PC02 <dbl>, PC03 <dbl>, PC04 <dbl>, PC05 <dbl>, PC06 <dbl>, PC07 <dbl>,
# PC08 <dbl>, PC09 <dbl>, PC10 <dbl>
При визуализации первых двух компонент получаем первые наблюдения. Так, PC01 хорошо выделяет тексты Ричардсона - самую многочисленную часть корпуса. Согласно второму графику, PC03 хорошо выделяет Троллопа, а PC04 содежит некоторый авторский сигнал Остин.
PC05 хорошо выделяет Стерна, а PC06 - Филдинга
Теперь изучим нагрузки компонент, чтобы проанализировать внимание нашей модели.
Так, для Троллопа характерны слова “to”, “may”, “favour”, “can”, “hope”, “will”. Для Теккерея - отрицательные значения по PC04: складывается впечатление, что у автора очень много женских персонажей, учитывая частотность местоимений женского рода. Скорее всего, вклад внёсла “Ярмарка тщеславия” с её ярким женским образом Бекки Шарп. Филдингу присущи отрицательные значения по PC06. И правда! Например, слово “squire” действительно очень часто встречается в двух романах Филдинга, т.к. главные герои обоих романов носят этот титул. Также для Филдинга характерно испольнование устаревшей формы глагола “have”: “hath”.
PLS
Для этого мтеода снижения размерности также зададим 10 компонент.
# A tibble: 2,413 × 20
avg_word_len avg_sent_len function_words ADJ ADV NOUN PROPN
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.295 0.375 0.292 0.00394 -0.216 -0.629 -0.445
2 -0.978 -0.296 -0.811 0.712 0.117 -1.30 0.117
3 -2.03 0.524 -0.0709 -0.751 2.03 -2.34 0.0864
4 -0.447 0.0290 0.797 -1.20 1.92 -2.16 -0.932
5 -0.245 0.474 -0.759 0.979 -0.0432 -0.871 -0.843
6 -1.26 -0.443 -0.191 -0.0261 0.131 -1.19 -1.11
7 0.0283 0.0372 -0.320 -0.117 -0.526 0.299 -1.16
8 0.332 0.176 0.956 -0.383 0.261 -0.926 -0.647
9 -1.53 0.0328 1.24 -0.941 1.62 -2.41 -0.727
10 -0.672 0.594 0.563 0.636 2.54 -1.20 -1.58
# ℹ 2,403 more rows
# ℹ 13 more variables: PUNCT <dbl>, VERB <dbl>, author <fct>, PLS01 <dbl>,
# PLS02 <dbl>, PLS03 <dbl>, PLS04 <dbl>, PLS05 <dbl>, PLS06 <dbl>,
# PLS07 <dbl>, PLS08 <dbl>, PLS09 <dbl>, PLS10 <dbl>
Результаты чем-то похожи на PCA. У Филдинга так же выделяются “immediately”, “surprise”, “hath”. Судя по формам обращения в составе PLS6, у Диккенса много мужским персонажей. По пятой компоненте хорошо кластеризуются два романа Стерна. Для них характерно употребление архаичной формы “quoth” вместо “said” и разговорного сокращения “’tis” вместо “it’s”. Несомненно, это сознательный стилистический приём, пародийное смешение высокой литературной традиции и лёгкого, ироничного повествования, разрушающего четвёртую стену. И всё это - нередко в одном предложении.
UMAP
При использовании UMAP по первой компоненте выделяется Ричардсон, по второй - Филдинг и Остин.
Третья компонента выделяет Стерна и Остин.
Рецепты для препроцессинга и выбор моделей
pca_rec <- base_rec |>
step_pca(all_numeric_predictors()[-c(1:9)], num_comp = tune())
pls_rec <- base_rec |>
step_pls(all_numeric_predictors()[-c(1:9)], outcome = "author", num_comp = tune())
umap_rec <- base_rec |>
step_umap(all_numeric_predictors()[-c(1:9)],
outcome = "author",
num_comp = tune(),
neighbors = tune("umap"),
min_dist = tune())
# Lasso&Ridge
lasso_spec <- multinom_reg(penalty = tune(), mixture = 1) |>
set_mode("classification") |>
set_engine("glmnet")
ridge_spec <- multinom_reg(penalty = tune(), mixture = 0) |>
set_mode("classification") |>
set_engine("glmnet")
# SVM
svm_spec <- svm_linear(cost = tune()) |>
set_mode("classification") |>
set_engine("LiblineaR")
# однослойная нейронная сеть
mlp_spec <- mlp(hidden_units = tune(),
penalty = tune(),
epochs = tune()) |>
set_engine("nnet") |>
set_mode("classification")
#деревья решений
bagging_spec <- bag_tree() |>
set_engine("rpart") |>
set_mode("classification")
# Flexible Discriminant Analysis
fda_spec <- discrim_flexible(prod_degree = tune()) |>
set_engine("earth")
# Regularized Discriminant Analysis
rda_spec <- discrim_regularized(frac_common_cov = tune(),
frac_identity = tune()) |>
set_engine('klaR')
# k-nearest
knn_mod <- nearest_neighbor(neighbors = tune("knn")) |>
set_engine("kknn") |>
set_mode("classification")
# логистическая регрессия
multinom_spec <- multinom_reg(penalty = tune(), mixture = tune()) |>
set_engine("glmnet") |>
set_mode("classification")
wflow_set <- workflow_set(
preproc = list(pca = pca_rec,
pls = pls_rec,
umap = umap_rec),
models = list(svm = svm_spec,
lasso = lasso_spec,
ridge = ridge_spec,
mlp = mlp_spec,
bagging = bagging_spec,
fda = fda_spec,
rda = rda_spec,
knn = knn_mod,
regression = multinom_spec),
cross = TRUE)
wflow_set# A workflow set/tibble: 27 × 4
wflow_id info option result
<chr> <list> <list> <list>
1 pca_svm <tibble [1 × 4]> <opts[0]> <list [0]>
2 pca_lasso <tibble [1 × 4]> <opts[0]> <list [0]>
3 pca_ridge <tibble [1 × 4]> <opts[0]> <list [0]>
4 pca_mlp <tibble [1 × 4]> <opts[0]> <list [0]>
5 pca_bagging <tibble [1 × 4]> <opts[0]> <list [0]>
6 pca_fda <tibble [1 × 4]> <opts[0]> <list [0]>
7 pca_rda <tibble [1 × 4]> <opts[0]> <list [0]>
8 pca_knn <tibble [1 × 4]> <opts[0]> <list [0]>
9 pca_regression <tibble [1 × 4]> <opts[0]> <list [0]>
10 pls_svm <tibble [1 × 4]> <opts[0]> <list [0]>
# ℹ 17 more rows
# A tibble: 27 × 9
wflow_id .config .metric mean std_err n preprocessor model rank
<chr> <chr> <chr> <dbl> <dbl> <int> <chr> <chr> <int>
1 pls_lasso Preproce… accura… 0.958 0.00328 5 recipe mult… 1
2 pls_svm Preproce… accura… 0.944 0.00422 5 recipe svm_… 2
3 pls_fda Preproce… accura… 0.918 0.00613 5 recipe disc… 3
4 pca_lasso Preproce… accura… 0.915 0.00652 5 recipe mult… 4
5 pls_knn Preproce… accura… 0.910 0.00728 5 recipe near… 5
6 pls_regression Preproce… accura… 0.905 0.00734 5 recipe mult… 6
7 pls_bagging Preproce… accura… 0.903 0.00454 5 recipe bag_… 7
8 pca_svm Preproce… accura… 0.894 0.00717 5 recipe svm_… 8
9 pls_ridge Preproce… accura… 0.889 0.00678 5 recipe mult… 9
10 pls_rda Preproce… accura… 0.873 0.00458 5 recipe disc… 10
# ℹ 17 more rows
Лучшие результаты по метрике accuracy принадлежат модели LASSO с препроцессором PLS. LASSO (Least Absolute Shrinkage and Selection Operator) — это вариация линейной регрессии, специально адаптированная для данных, которые демонстрируют сильную мультиколлинеарность. Видимо, тренировочные данные демонтрируют избыточность даже после снижения размерности (в этом точно можно заподозрить части речи, например, зависимости частотностей сущ. и глаг. выглядят обратными).
# A tibble: 1 × 3
penalty num_comp .config
<dbl> <int> <chr>
1 0.0000000001 4 Preprocessor1_Model1
Метрики на тестовой выборке.
# A tibble: 3 × 4
.metric .estimator .estimate .config
<chr> <chr> <dbl> <chr>
1 f_meas macro 0.931 Preprocessor1_Model1
2 accuracy multiclass 0.952 Preprocessor1_Model1
3 roc_auc hand_till 0.996 Preprocessor1_Model1
На тепловой карте показана успешность определения авторов на тестовой выборке. Модель отлично справилась почти со всеми писателями, допустив однако больше всего ошибок с текстами Ш.Бронте и Ч.Диккенса, причём именно этих двух авторов модель перепутала между собой. Также похожими оказались тексты сестёр Бронте. Если с ними всё ясно, то об их связи с Диккенсом историки ещё напишут разоблачительные страницы. Ох уж эти загадочные викторианцы)()()()()
Интерпретация модели
Судя по графику наиболее важных предикторов для каждого из авторов нашего корпуса, можно сделать следующие выводы: - тексты Эллиота, Стерна и А.Бронте написаны длинными предложениями, - Троллоп и Остин часто употребляют имена собственные, - тексты Диккенса изобилуют стоп-словами и пунктуацией, - Троллоп же скуп на пунктуацию и предпочитает использовать короткие слова (скорее всего, это артефакты лемматизации сокращённых форм). Некоторые из сделанных нами выше наблюдений, собранных благодаря визуализациям после снижения размерности (PLS), дублируются и здесь.