[МУЗЫКА]
[МУЗЫКА] В
рамках данного видео мы рассмотрим коллекцию, которую собрали мои коллеги.
Эта коллекция представляет собой отрывки из произведений классических
русских прозаиков XIX и XX века.
Сперва импортируем некоторые модули.
Нам потребуется sqlalchemy — это библиотека для
работы с базами данных в формате SQLite,
pandas — для того чтобы высчитывать данные как dataframe и оперировать с ними.
Знакомые вам numpy, matplotlib и seaborn.
Кроме того, нам потребуется nltk — natural language toolkit.
Это отдельная библиотека для работы с текстом на естественном языке.
А также pymorphy2 — некоторый модуль, который позволяет работать с
текстами конкретно на русском языке, специализированный модуль.
А также sklearn — импортируем некоторые пакеты и классы из него.
Кроме того, нам потребуется модуль itertools — это специальный модуль
для работы с итераторами.
Считаем базу данных в dataframe и покажем первые колонки.
Как вы видите, нам попался Бунин и некоторые его тексты.
Перед осуществлением какого-либо анализа текст необходимо обработать.
Текст — это неструктурированные данные,
и алгоритмы машинного обучения неспособным оперировать ими напрямую,
в отличие от численных векторов, с которыми мы работали раньше.
Поэтому давайте создадим объект MorphAnalyser, который нам пригодится,
модуля pymorphy2 и напишем некоторые функции.
is_cyr_word — это функция, которая проверяет,
написано ли это слово на кириллице.
Она достаточно простая.
process_text — это основная функция,
которая занимается препроцессингом, предобработкой, нашей текста.
При помощи функции wordpunct_tokenize модуля nltk мы разделим наш
текст на отдельные токены — слова.
Далее отфильтруем те слова,
которые написаны не на кириллице, оставим только русскую речь.
Как вы можете помнить, многие авторы XIX и XX века любили
вставлять в свои произведения отрывки на иностранных языках.
А потом приведем слова к нормальной форме.
В данном случае, когда мы используем pymorphy2, мы их лемматизируем,
то есть канонизируем и приводим к некоторому единому виду, каноническому.
Например, в случае с существительными — это единственное число, мужской род,
именительный падеж.
Как вы понимаете,
данные действия крайне сильно уменьшают размерность словаря и позволяют нам
намного более удачно преобразовывать слова в векторное пространство.
Что же, давайте предобработаем наш текст и сохраним его в отдельную CSV-таблицу.
Это может занять некоторое время.
Учитывая, что обработка текстов — это крайне трудоемкий процесс,
то это может занять даже минут 20–30 в зависимости от вашего ноутбука.
Считаем нашу таблицу, и давайте посмотрим, а сколько конкретных
отрывков принадлежит каждому из авторов, как распределены тексты по авторам.
И, кроме того, мы знаем, какие авторы есть у нас в таблице.
У нас есть Платонов, Чехов, Пушкин, Пастернак, Бунин, Гончаров, Тургенев,
Толстой, Гоголь и Достоевский.
Меньше всего текста у нас имеется для Пушкина,
больше всего — для Платонова и Гончарова.
Давайте импортируем список стоп-слов.
Одна из самых ходовых гипотез в преанализе естественных языков — это гипотезы,
связанные со встречаемостью.
Так, например, есть такая гипотеза, которая находит свое подтверждение в
практике: что самые частые слова несут меньше всего семантической нагрузки.
В данном случае мы говорим о стоп-словах.
И существуют уже специально оформленные списки стоп-слов.
Такие слова принято не рассматривать при анализе и изымать их их корпуса,
поскольку они не значимы.
Кроме того, подобная операция достаточно сильно сокращает процессорное время.
Давайте импортируем список стоп-слов, встроенные в nltk.
И посмотрим его подробнее.
Как вы видите, здесь местоимения, союзы и частицы в основном.
Давайте векторизуем наш текст и составим некоторые простенький pipeline.
Сначала мы векторизуем текст — это степ pipeline tf-idf,
а потом применяем классификатор — степ clf.
Кроме того, напишем вспомогательную функцию.
Одна из этих функций берет наш pipeline, train и test set,
обучает его и возвращает нам классификатор score.
А вторая рисует confusion_matrix — матрицу ошибок,
которая показывает, насколько мы ошиблись при классификации.
Что же, давайте запустим.
В качестве метрики мы будем использовать F-меру.
Это достаточно хорошая метрика при задачах классификации.
Ну что же, наш support vector
classifier отработал на 0.88 F_score, и это достаточно неплохой результат.
Как вы можете видеть по матрице, хуже всего отделяется Пушкин —
в случае с Пушкиным мы угадали его только в 61 % случаев.
Лучше всего отделяется Гончаров и Платонов — 92 и 97 %.
Посмотрим на другой способ представления данных — Word2Vec.
Word2Vect, в отличие от tf-idf модели,
преобразует разреженное пространство словаря в более сжатое пространство rn.
Правильно подобрав параметры модели, в том числе и n-размерность пространства,
можно добиться того, что вектора, близкие в смысле косинусной
меры близости в пространстве rn, будут близки и семантически, то есть будут
близки семантически слова, которые будут соответствовать этим векторам.
Воспользуемся реализацией Word2Vec из пакета gensim.
Для этого сначала нужно разбить наш текст на предложения,
потому что Word2Vec следует обучать на предложениях.
Для этого загрузим некоторые токенайзеры — на самом деле,
мы сейчас используем токенайзеры для английского языка,
но в случае с разбиением текста на предложение это почти не влияет.
А в самом nltk, к несчастью, нет токенайзера для русского.
Ну что же, давайте разобъем наш текст на предложения и сохраним его на диск,
потому что опять же это может занять достаточно долгое время и будет удобно
читать его с жесткого диска, а не обрабатывать все заново.
Что же, считаем получившийся результат и обучим модель Word2Vec.
Воспользуемся реализацией из пакета gensim.
Зададим некоторые параметры модели,
подробнее о них вы можете узнать в документации gensim.
И настроим logging, для того чтобы нам выводились данные об обучении модели,
а также обучим эту модель.
Как вы видите, в процессе
работы наша модель выводит сообщения о прогрессе.
И опять же сохраним нашу модель на диск.
Что же, мы обучили нашу модель.
Давайте посмотрим, что же умеет Word2Vec.
Фактически Word2Vec — это нейросеть, которая решает задачу восстановления слова
по его контексту или, наоборот, контекста по слову.
Как вы понимаете, сконструировать такую задачу из корпуса текстов несложно,
а вектора, которые получаются на предпоследнем слове этой сети,
очень хорошо схватывают семантическую близость слов.
Так, например,
в имплементации модели от Word2Vec встроены различные интересные особенности.
Например, можно находить слово, которое не подходит,
то есть найти лишнее слово из перечисленного.
Или же наоборот: найти слово наиболее похожее на то или другое.
Давайте посмотрим, какие слова обнаружит модель, обученная на нашем корпусе.
И, действительно, из слов «отец», «сын», «мать» и «кот»
она посчитала лишним кота, а из Парижа, Москвы, Петербурга и Франции — Францию.
Отличать животных от людей, а страны от городов наша модель научилась.
Однако если мы попробуем копнуть чуть-чуть глубже и вывести слова,
наиболее похожие на заданные, наиболее похожие с точки зрения модели,
на слово «отец» будут слова «жена», «матерь», «муж» и «сын».
А вот со словом корабль уже несколько сложнее.
Более похожими с точки зрения модели считаются слова «остров», «завод»,
«судно», «кладбище», «пароход» и так далее.
Возможно, это связано с тем, что у нас не настолько большой корпус текста,
обычно модели Word2Vec обучают на куда больших корпусах текста.
Давайте воспользуемся другой моделью,
обученной на корпусе тектов НКРЯ (Национальный корпус русского языка).
Он достаточно большой, и наверняка слова из него будут куда более интересными.
Что же, считаем эту модель, скачать ее вы можете по ссылке, приведенной в описании.
Загрузим и немножечко изменим слова, потому что слова в НКРЯ представлены
в несколько специфичном виде, несколько техническом.
И проведем те же самые операции.
Наша модель загружается.
Что же, как вы видите, с котом и Францией все удалось — наиболее близкими к
этому слову оказались «мать», «сын», «дед» и «брат».
Вполне логично.
А наиболее близкими к слову «корабль» оказались «судно», «фрегат»,
«эскадра» и «шлюпка».
Тоже вполне неплохой результат для нашей модели.
Давайте переобучим наш классификатор: будем использовать в качестве входных
параметров на последнем шаге не tf-idf-вектора, а вектора модели Word2Vec.
Необходимо как-либо преобразовать вектора, отвечающее за отдельные слова,
к некоторому одному, который бы характеризовал кусок текста.
Одной из таких практик является td-idf-усреднение.
Мы просто берем каждое из наших векторов, отвечающий за каждое из слов, и усредняем
его с весом, пропорциональны весу этого слова в tf-idf векторе данного документа.
Вот мы усреднили наши вектора, взвесив их по схеме tf-idf,
Давайте обучим классификатор.
В данном случае мы воспользуемся другой моделью ExtraTreesClassifier.
Эта модель принадлежит к классу ансамблей, практика показывает,
что такие модели весьма неплохо работают с Word2vec представлениями текстов.
Давайте обучим нашу модель и посчитаем F score.
Хмм, всего 0,52.
Да, это, конечно, не так интересно, как 0,88, который выдал линейный MSVM.
Интересно, а почему?
Давайте попробуем исследовать этот вопрос.
Давайте уменьшим объём обучающей выборки и посмотрим,
как на это отреагирует Word2Vec модель, и, соответственно, TF-IDF и линейная модель.
Пробежимся в цикле по некоторому проценту,
который мы оставим от нашей обучающей выборки и запишем в массивы
F score classifier и F score support vector classifier.
И, давайте, нарисуем это на графике.
Красным цветом мы показали score случайного леса,
а синим, соответственно, score support vector classifier.
И, как вы можете заметить, несмотря на то, что support vector classifier, обыгрывая
случайный лес, с уменьшением размера выборки он очень быстро деградирует,
а случайный лес, наоборот, работает примерно с одним и тем же качеством.
Что ж, может быть наша модель и не очень хороша в том, чтобы отгадывать конкретного
автора, но, по крайней мере, она смогла получить дополнительные знания
из внешнего источника, которым являются вектора, обученные на НКРЯ.
Однако, всё-таки, почему такая простая линейная модель на такой,
казалось бы, интересной задаче,
как классификация автора показывает такие высокие результаты?
Давайте обратимся для этого к библиотеке eli5.
Эта библиотека не входит в стандартные патенты Анаконды, но, однако,
её можно поставить с помощью pip, менджера пакетов, и с GitHub, напрямую.
Что ж, давайте воспользуемся функциями, которые предлагает eli5.
Импортируем eli5 и некоторые её внутренние пакеты,
а также импортируем модель SGDClassifier, эта модель с параметром modified Huber
на самом деле аналогична линейному SVM, но при этом библиотека eli5
умеет работать именно с такими моделями, основанными на градиентном спуске.
Давайте обучим наш pipeline и посчитаем F score.
0,87, что ж, это не сильно отличается от показателей LinearSVC.
Давайте воспользуемся методом show_prediction библиотеки eli5.
Этот метод позволяет нам для конкретного куска текста и
всех возможных авторов определить, а какие слова с точки зрения модели,
линейной модели, оказались наиболее важными.
Соответственно, цветом обозначена значимость того или иного слова: чем ярче,
тем оно более или менее важное.
Соответственно, зелёный — это положительное,
а красный — это отрицательное влияние.
Как вы видите, реальным автором этого текста является Лев Николаевич Толстой.
И да, все остальные авторы обладают крайне низкой вероятностью
быть принятыми за реального, кроме Льва Николаевича.
У него целых 70%, что весьма неплохо.
Давайте воспользуемся другой функцией, встроенной в eli5.
Это функция show_weights, эта функция показывает признаки, наиболее важные
для модели при определении, к какому автору отнести конкретный кусок текста.
И что же мы тут видим?
Для каждого автора наша модель была склонна выбирать имена собственные:
Егорушка — для Чехова, Пугачёв — для Пушкина, для Пастернака,
например, — Живаго.
Очевидно, что это имена персонажей.
То есть, действительно, наша модель просто выучила имена персонажей,
которые были характерны для данных авторов.
И никакой реальной стилистики, никакой реальной семантики, никакого реального
определения конкретного автора наша модель предоставить нам не смогла.
Ну что ж, хотя бы мы поняли, почему у нас такой высокий результат.
В рамках наших занятий мы познакомились с языком Python и платформой Anaconda.
Рассмотрели различные библиотеки машинного обучения и научились применять полученные
знания на практике.
На этом я прощаюсь с вами.