
Как различать британскую и американскую литературу с помощью машинного обучения
Однажды мне стало интересно, отличается ли британская и американская литература с точки зрения выбора слов, и если отличается, удастся ли мне обучить классификатор, который бы различал литературные тексты с точки зрения частоты использованных слов. Различать тексты, написанные на разных языках, довольно легко, мощность пересечения множества слов небольшая относительно множества слов в выборке. Классификация текста по категориям «наука», «христианство», «компьютерная графика», «атеизм», — всем известный hello world среди задач по работе с частотностью текста. Передо мной стояла более сложная задача, так как я сравнивала два диалекта одного языка, а тексты не имели общей смысловой направленности.
Самый долгий этап машинного обучения — это извлечение данных. Для обучающей выборки я использовала тексты с Project Gutenberg, их можно свободно скачивать. Список американских и британских авторов я выкачала из википедии. Сложность заключалась в том, чтобы найти соответствие по имени автора. На сайте проекта реализован хороший поиск по именам, но парсить сайт запрещено, вместо этого предлагается использовать архив с метаданными. Это означало, что мне нужно решать нетривиальную задачу совпадения имен (Sir Arthur Ignatius Conan Doyle и Doyle, C. — одни и те же люди, а Doyle, M. E. уже нет) и делать это с очень высокой точностью. Вместо этого я, пожертвовав размером выборки в пользу точности и экономии своего времени, выбрала в качестве уникального идентификатора ссылку на википедию автора, которая была включена в некоторые файлы метаданных. Так я получила около 1600 британских текстов и 2500 американских и принялась обучать классификатор.
При всех операциях я использовала пакет sklearn. Первый шаг после сбора и анализа данных — это препроцессинг, для которого я взяла CountVectorizer. Он принимает на вход массив текстовых данных и возвращает вектор признаков. Далее требуется представить признаки в числовом формате, так как классификатор работает с числовыми данными. Для этого нужно вычислить tf-idf, term frequency — inverted document frequency, используя TfidfTransformer.
Короткий пример о том, как это делается и зачем:
Возьмем слово “the” и посчитаем количество вхождений этого слова в тексте А. Пусть у нас будет 100 вхождений, а общее количество слов в документе 1000,
tf(“the”) = 100/1000 = 0.1
Далее возьмем слово “sepal” (чашелистик), которое встретилось 50 раз,
tf(“sepal”) = 50/1000 = 0.05
Чтобы посчитать inverted document frequency для этих слов, нужно взять логарифм от отношения количества текстов, в которых есть хоть одно вхождение этого слова, к общему количеству текстов. Если всего текстов 10000, и в каждом есть слово “the”,
idf(“the”) = log(10000/10000) = 0
tf-idf(“the”) = idf(“the”) * tf(“the”) = 0 * 0.1 = 0
Слово “sepal” гораздо более редкое, и встретилось только в 5 текстах, поэтому
idf(“sepal”) = log(10000/5) = 7.6
tf-idf(“sepal”) = 7.6 * 0.05 = 0.38
Таким образом, частые слова имеют минимальный вес, и специфичные редкие — большой, и по большому вхождению слова “sepal” в текст можно предположить, что он как-то связан с ботаникой.
Теперь, когда данные представлены как набор признаков, нужно обучить классификатор. Я работаю с текстом, который представлен как разреженные данные, поэтому оптимальным вариантом стал линейный классификатор, хорошо справляющийся с задачами классификации с большим количеством признаков. И CountVectorizer, и TF-IDFTransformer, и SGD я обучала с параметрами по умолчанию. Можно отдельно работать с каждым этапом, но удобнее использовать pipeline:
pipeline = Pipeline([
('vect', CountVectorizer()),
('tfidf', TfidfTransformer()),
('clf', SGDClassifier()),
])
Проанализировав график точности от размера выборки, я заметила сильные колебания точности даже на больших объемах выборки, что свидетельствовало о том, что классификатор очень сильно зависим от конкретной выборки, а значит мало эффективен, и требуются существенные улучшения. Получив список весов классификатора, я заметила часть проблемы: алгоритм переобучался на частых словах типа “of” и “he”, которые по сути являются шумом. Эта проблема легко решается удалением подобных слов из признаков, и задается параметром CountVectorizer stop_words = 'english' или вашим собственным списком слов. Еще немного улучшило точность, удаление некоторых популярных общеупотребимых слов. Убрав стоп-слова, я получила улучшение точности до 0.85.
Далее я занялась настройкой параметров c помощью GridSearchCV. Этот способ выявляет лучшую комбинацию параметров для CountVectorizer, TfidfTransformer и SGDClassifier, поэтому это очень долгий процесс, у меня он считался около суток. В итоге получила такой pipeline:
pipeline = Pipeline([
('vect', CountVectorizer(stop_words = modifyStopWords(), ngram_range = (1, 1))),
('tfidf', TfidfTransformer(use_idf = True, norm = 'l2', smooth_idf = True)),
('clf', SGDClassifier(alpha=0.001, fit_intercept = True, n_iter = 10, penalty = 'l2', loss = 'epsilon_insensitive')),
])
Итоговая точность — 0.89.
Теперь самое интересное для меня: какие слова указывают на происхождение текста. Вот список слов, отсортированный по убыванию модуля веса в классификаторе:
Американский текст: dollars, new, york, girl, gray, american, carvel, color, city, ain, long, just, parlor, boston, honor, washington, home, labor, got, finally, maybe, hodder, forever, dorothy, dr
Британский текст: round, sir, lady, london, quite, mr, shall, lord, grey, dear, honour, having, philip, poor, pounds, scrooge, soames, things, sea, man, end, come, colour, illustration, english, learnt
Развлекаясь с классификатором, я получила самых «британских» авторов из числа американцев и самых «американских» британцев (изящный способ рассказать о том, как сильно может ошибаться мой классификатор):
Cамые «британские» американцы:
- Бёрнетт, Фрэнсис Элиза (родилась в Англии, в возрасте 17 лет переехала в США, поэтому отношу ее к американцам)
- Генри Джеймс (родился в США, в 33 года эмигрировал в Великобританию)
- Уистер, Оуэн
- Мэри Робертс Рейнхарт (как видим, называемая американской Агатой Кристи не без причины)
- Уильям Мак-Фи (как и Бёрнетт, переехал в США в юном возрасте)
Cамые «американские» британцы:
- Ридьярд Киплинг (прожил несколько лет в США, попал в список благодаря “American Notes”)
- Энтони Троллоп (опять же виноваты американские топонимы в его “North America”)
- Фредерик Марриет (возможно, одного бы названия “Narrative of the Travels and Adventures of Monsieur Violet in California, Sonara, and Western Texas” хватило бы, чтобы запутать классификатор)
- Арнольд Беннетт (спасибо его “Your United States: Impressions of a first visit”)
- Филлипс Оппенхейм
А также самых «британских» британцев и «американских» американцев (потому что классификатор все же хорош).
Aмериканцы:
- Франсис Хопкинсон Смит
- Гэмлин Гарленд
- Джордж Эйд
- Чарльз Дадли Уорнер
- Марк Твен
Британцы:
- Джордж Мередит
- Сэмюэл Ричардсон
- Джон Голсуорси
- Гилберт Кит Честертон
- Энтони Троллоп
На попытку сделать такой классификатор меня подтолкнул твит @TragicAllyHere:
I would love to be British. Drinking my leaf water and staring at a huge clock from my red phone booth, adding extra letters to wourds.
Код можно взять здесь, там же доступен уже обученный классификатор.
Comments 21
Only users with full accounts can post comments. Log in, please.