Как различать британскую и американскую литературу с помощью машинного обучения

в 8:25, , рубрики: machine learning, natural language processing, python, sklearn, машинное обучение

Однажды мне стало интересно, отличается ли британская и американская литература с точки зрения выбора слов, и если отличается, удастся ли мне обучить классификатор, который бы различал литературные тексты с точки зрения частоты использованных слов. Различать тексты, написанные на разных языках, довольно легко, мощность пересечения множества слов небольшая относительно множества слов в выборке. Классификация текста по категориям «наука», «христианство», «компьютерная графика», «атеизм», — всем известный hello world среди задач по работе с частотностью текста. Передо мной стояла более сложная задача, так как я сравнивала два диалекта одного языка, а тексты не имели общей смысловой направленности.

image

Самый долгий этап машинного обучения — это извлечение данных. Для обучающей выборки я использовала тексты с 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.

Код можно взять здесь, там же доступен уже обученный классификатор.

Автор: omruruch

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js