├── HW
├── hw1.ipynb
├── hw2.ipynb
├── hw3.ipynb
└── hw4.ipynb
├── README.md
├── lectures
├── 10_sumamrization_simplification.pdf
├── 1_Intro.pdf
├── 2_embeddings.pdf
├── 3_text-classification.pdf
├── 4_lm.pdf
├── 4_seq-model.pdf
├── 5_Anya_TM.pdf
├── 5_VSM.pdf
├── 6_mt_attn_transformer.pdf
├── 6_seq2seq.pdf
├── 8_sesame_street.pdf
└── 9_QA.pdf
└── seminars
├── 1
├── 1_preprocessing.ipynb
├── 1_regex.ipynb
└── 1_regex.pdf
├── 2
├── 2_bonus_topic_models.ipynb
└── 2_embeddings.ipynb
├── 3
└── 3_classification.ipynb
├── 4
├── images
│ ├── .DS_Store
│ ├── LSTM.png
│ ├── LSTM_rnn.png
│ ├── bilstm_crf_model.png
│ ├── dino.jpg
│ ├── dino.png
│ ├── dinos3.png
│ ├── rnn.png
│ ├── rnn_cell_backprop.png
│ ├── rnn_step_forward.png
│ ├── understanding_lstms.jpg
│ └── word_representation_model.png
└── sem4_language_models.ipynb
├── 5
├── 5_Keywords_and_Topic _Modelling.ipynb
├── img
│ ├── LDA.png
│ ├── artm.jpg
│ ├── bow.png
│ ├── ldavis.png
│ ├── lsa.gif
│ ├── matrix.png
│ ├── plsi.png
│ └── svd.png
├── polkrug_lem.txt
└── rus_stopwords.txt
├── 6
└── 6_seq2seq.ipynb
├── 7
└── Baseline_AIJ.ipynb
├── 8
├── constituency_parsing.png
├── recursiveNN.jpg
├── recursiveNN_formula.jpg
├── rus_tree.png
├── sem8_syntax.ipynb
└── sentiment_recursiveNN.png
└── 12
├── .DS_Store
├── active_learning.png
├── sem12-active-learning.ipynb
└── spam_text_classification_data.csv
/HW/hw1.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Домашнее задание 1\n",
8 | "## Harry Potter and the Action Prediction Challenge from Natural Language\n",
9 | "\n",
10 | "*deadline*: 2 октября 2019, 23:59\n",
11 | "\n",
12 | "В этом домашнем задании вы будете работать с корпусом Harry Potter and the Action Prediction Challenge. Корпус собран из фанфиков о Гарри Поттере и состоит из двух частей: 1) сырые тексты, 2) фрагменты текстов, описывающих ситуацию, в которой произнесено заклинание.\n",
13 | "\n",
14 | "Корпус описан в статье: https://arxiv.org/pdf/1905.11037.pdf\n",
15 | "\n",
16 | "David Vilares and Carlos Gómez-Rodríguez. Harry Potter and the Action Prediction Challenge from Natural Language. 2019 Annual Conference of the North American Chapter of the Association for Computational Linguistics. To appear.\n",
17 | "\n",
18 | "Код для сбора корпуса находится в репозитории: https://github.com/aghie/hpac . Корпус можно скачать по инструкции из этого репозитория, но для экономии времени авторы задания уже скачали и подготовили данные к работе. \n",
19 | "\n",
20 | "Ссылки на собранный корпус: \n",
21 | "* Сырые тексты: https://www.dropbox.com/s/23xet9kvbqna1qs/hpac_raw.zip?dl=0\n",
22 | "* Токенизированные тексты в нижнем регистре: https://www.dropbox.com/s/gwfgmomdbetvdye/hpac_lower_tokenized.zip?dl=0\n",
23 | "* train-test-dev: https://www.dropbox.com/s/3vdz0mouvex8abd/hpac_splits.zip?dl=0\n",
24 | "\n",
25 | "Части 1, 2 задания должны быть выполнены на полных текстах (сырых или предобработанных -- на ваше усмотрение), Часть 3 – на разбиение на тестовое, отладочное и обучающее множества. Тестовое множество должно быть использовано исключительно для тестирования моделей, обучающее и отладочное – для выбора модели и параметров. \n",
26 | "\n",
27 | "В статье и репозитории вы найдете идеи, которые помогут вам выполнить домашнее задание. Их стоит воспринимать как руководство к действию, и не стоит их копировать и переиспользовать. Обученные модели использовать не нужно, код для их обучения можно использовать как подсказку. \n",
28 | "\n",
29 | "## ПРАВИЛА\n",
30 | "1. Домашнее задание выполняется в группе до 3-х человек.\n",
31 | "2. Домашнее задание сдается через anytask, инвайты будут дополнительно высланы.\n",
32 | "3. Домашнее задание оформляется в виде отчета либо в .pdf файле, либо ipython-тетрадке. \n",
33 | "4. Отчет должен содержать: нумерацию заданий и пунктов, которые вы выполнили, код решения, и понятное пошаговое описание того, что вы сделали. Отчет должен быть написан в академическом стиле, без излишнего использования сленга и с соблюдением норм русского языка.\n",
34 | "5. Не стоит копировать фрагменты лекций, статей и Википедии в ваш отчет.\n",
35 | "6. Отчеты, состоящие исключительно из кода, не будут проверены и будут автоматически оценены нулевой оценкой.\n",
36 | "7. Плагиат и любое недобросоветсное цитирование приводит к обнуление оценки. \n",
37 | "\n",
38 | "\n",
39 | "## Часть 1. [2 балла] Эксплоративный анализ \n",
40 | "1. Найдите топ-1000 слов по частоте без учета стоп-слов.\n",
41 | "2. Найдите топ-10 по частоте: имен, пар имя + фамилия, пар вида ''профессор'' + имя / фамилия. \n",
42 | "\n",
43 | "[бонус] Постройте тематическую модель по корпусу HPAC.\n",
44 | "\n",
45 | "[бонус] Найдите еще что-то интересное в корпусе (что-то специфичное для фанфиков или фентези-тематики)\n",
46 | "\n",
47 | "## Часть 2. [2 балла] Модели представления слов \n",
48 | "Обучите модель представления слов (word2vec, GloVe, fastText или любую другую) на материале корпуса HPAC.\n",
49 | "1. Продемонстрируйте, как работает поиск синонимов, ассоциаций, лишних слов в обученной модели. \n",
50 | "2. Визуализируйте топ-1000 слов по частоте без учета стоп-слов (п. 1.1) с помощью TSNE или UMAP (https://umap-learn.readthedocs.io).\n",
51 | "\n",
52 | "## Часть 3. [5 баллов] Классификация текстов\n",
53 | "Задача классификации формулируется так: данный фрагмент фанфика описывают какую-то ситуацию, которая предшествует произнесению заклинания. Требуется по тексту предсказать, какое именно заклинание будет произнесено. Таким образом, заклинание - это фактически метка класса. Основная мера качества – macro $F_1$.\n",
54 | "Обучите несколько классификаторов и сравните их между собой. Оцените качество классификаторов на частых и редких классах. Какие классы чаще всего оказываются перепутаны? Связаны ли ошибки со смыслом заклинаний?\n",
55 | "\n",
56 | "Используйте фрагменты из множества train для обучения, из множества dev для отладки, из множества test – для тестирования и получения итоговых результатов. \n",
57 | "\n",
58 | "1. [1 балл] Используйте fastText в качестве baseline-классификатора.\n",
59 | "2. [2 балла] Используйте сверточные сети в качестве более продвинутого классификатора. Поэкспериментируйте с количеством и размерностью фильтров, используйте разные размеры окон, попробуйте использовать $k$-max pooling. \n",
60 | "3. [2 балла] Попробуйте расширить обучающее множество за счет аугментации данных. Если вам понадобится словарь синонимов, можно использовать WordNet (ниже вы найдете примеры).\n",
61 | "\n",
62 | "[бонус] Используйте результат max pooling'а как эмбеддинг входного текста. Визуализируйте эмбеддинги 500-1000 предложений из обучающего множества и изучите свойства получившегося пространства.\n",
63 | "\n",
64 | "[бонус] Используйте ваш любимый классификатор и любые (честные) способы повышения качества классификации и получите macro $F_1$ больше 0.5.\n",
65 | "\n",
66 | "## Часть 4. [1 балл] Итоги\n",
67 | "Напишите краткое резюме проделанной работы. Читали ли вы сами Гарри Поттера или фанфики о нем и помогло ли вам знание предметной области в выполнении домашнего задания?"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {},
73 | "source": [
74 | "### Данные\n",
75 | "Сырые тексты "
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": null,
81 | "metadata": {
82 | "jupyter": {
83 | "outputs_hidden": true
84 | }
85 | },
86 | "outputs": [],
87 | "source": [
88 | "!unzip hpac_source"
89 | ]
90 | },
91 | {
92 | "cell_type": "code",
93 | "execution_count": null,
94 | "metadata": {},
95 | "outputs": [],
96 | "source": [
97 | "!ls hpac_source | wc -l"
98 | ]
99 | },
100 | {
101 | "cell_type": "code",
102 | "execution_count": null,
103 | "metadata": {},
104 | "outputs": [],
105 | "source": [
106 | "!unzip hpac_splits"
107 | ]
108 | },
109 | {
110 | "cell_type": "markdown",
111 | "metadata": {},
112 | "source": [
113 | "train, test, dev файлы"
114 | ]
115 | },
116 | {
117 | "cell_type": "code",
118 | "execution_count": null,
119 | "metadata": {},
120 | "outputs": [],
121 | "source": [
122 | "import pandas as pd\n",
123 | "df = pd.read_csv('hpac_splits/hpac_training_128.tsv', sep = '\\t', header = None)"
124 | ]
125 | },
126 | {
127 | "cell_type": "code",
128 | "execution_count": null,
129 | "metadata": {},
130 | "outputs": [],
131 | "source": [
132 | "df.head()"
133 | ]
134 | },
135 | {
136 | "cell_type": "code",
137 | "execution_count": null,
138 | "metadata": {},
139 | "outputs": [],
140 | "source": [
141 | "df.iloc[0][1], df.iloc[0][2]"
142 | ]
143 | },
144 | {
145 | "cell_type": "markdown",
146 | "metadata": {},
147 | "source": [
148 | "### Как использовать WordNet из nltk?"
149 | ]
150 | },
151 | {
152 | "cell_type": "code",
153 | "execution_count": null,
154 | "metadata": {},
155 | "outputs": [],
156 | "source": [
157 | "# скачиваем WordNet\n",
158 | "import nltk\n",
159 | "nltk.download('wordnet')"
160 | ]
161 | },
162 | {
163 | "cell_type": "code",
164 | "execution_count": null,
165 | "metadata": {},
166 | "outputs": [],
167 | "source": [
168 | "# слово -> множество синсетов (синонимов разных смыслов исходного слова)\n",
169 | "from nltk.corpus import wordnet as wn\n",
170 | "wn.synsets('magic')"
171 | ]
172 | },
173 | {
174 | "cell_type": "code",
175 | "execution_count": null,
176 | "metadata": {},
177 | "outputs": [],
178 | "source": [
179 | "# посмотрим, что внутри одного синсета\n",
180 | "wn.synsets('magic')[1].lemmas()[0]"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": null,
186 | "metadata": {},
187 | "outputs": [],
188 | "source": [
189 | "# возьмем лемму одного из слов из синсета\n",
190 | "wn.synsets('magic')[1].lemmas()[-1].name()"
191 | ]
192 | }
193 | ],
194 | "metadata": {
195 | "kernelspec": {
196 | "display_name": "Python 3",
197 | "language": "python",
198 | "name": "python3"
199 | },
200 | "language_info": {
201 | "codemirror_mode": {
202 | "name": "ipython",
203 | "version": 3
204 | },
205 | "file_extension": ".py",
206 | "mimetype": "text/x-python",
207 | "name": "python",
208 | "nbconvert_exporter": "python",
209 | "pygments_lexer": "ipython3",
210 | "version": "3.6.0"
211 | }
212 | },
213 | "nbformat": 4,
214 | "nbformat_minor": 4
215 | }
216 |
--------------------------------------------------------------------------------
/HW/hw2.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Домашнее задание 2\n",
8 | "## Named Entety Recognition and Event Extraction from Literary Fiction\n",
9 | "\n",
10 | "deadline: 30 октября 2019, 23:59\n",
11 | "\n",
12 | "В этом домашнем задании вы будете работать с корпусом LitBank. Корпус собран из популярных художественных произведений на английском языке и сожержит разметку по именованным сущностям и событиям. Объем корпуса таков: 100 текстов по примерно 2000 слов каждый. \n",
13 | "\n",
14 | "Корпус описан в статьях:\n",
15 | "* David Bamman, Sejal Popat, Sheng Shen, An Annotated Dataset of Literary Entities http://people.ischool.berkeley.edu/~dbamman/pubs/pdf/naacl2019_literary_entities.pdf\n",
16 | "* Matthew Sims, Jong Ho Park, David Bamman, Literary Event Detection, http://people.ischool.berkeley.edu/~dbamman/pubs/pdf/acl2019_literary_events.pdf\n",
17 | "\n",
18 | "Корпус доступен в репозитории проекта: https://github.com/dbamman/litbank\n",
19 | "\n",
20 | "Статья и код, использованный для извлечения именованных сущностей: \n",
21 | "* Meizhi Ju, Makoto Miwa and Sophia Ananiadou, A Neural Layered Model for Nested Named Entity Recognition, https://github.com/meizhiju/layered-bilstm-crf\n",
22 | "\n",
23 | "Структура корпуса устроена так. \n",
24 | "Первый уровень: \n",
25 | "* entities -- разметка по сущностям\n",
26 | "* events -- разметка по сущностям\n",
27 | "\n",
28 | "\n",
29 | "В корпусе используются 6 типов именованных сущностей: PER, LOC, ORG, FAC, GPE, VEH (имена, локации, организации, помещения, топонимы, средства перемещния), допускаются вложенные сущности. \n",
30 | "\n",
31 | "События выражается одним словом - *триггером*, которое может быть глагом, прилагательным и существительным. В корпусе описаны события, которые действительно происходят и не имеют гипотетического характера. \n",
32 | "Пример: she *walked* rapidly and resolutely, здесь *walked* -- триггер события. Типы событий не заданы. \n",
33 | "\n",
34 | "\n",
35 | "\n",
36 | "Второй уровень:\n",
37 | "* brat -- рабочие файлы инструмента разметки brat, ann-файлы содержат разметку, txt-файлы – сырые тексты \n",
38 | "* tsv -- tsv-файлы содержат разметку в IOB формате,\n",
39 | "\n",
40 | "\n",
41 | "В статье и репозитории вы найдете идеи, которые помогут вам выполнить домашнее задание. Их стоит воспринимать как руководство к действию, и не стоит их копировать и переиспользовать. Обученные модели использовать не нужно, код для их обучения можно использовать как подсказку. \n",
42 | "\n",
43 | "## ПРАВИЛА\n",
44 | "1. Домашнее задание выполняется в группе до 3-х человек.\n",
45 | "2. Домашнее задание сдается через anytask, инвайты будут дополнительно высланы.\n",
46 | "3. Домашнее задание оформляется в виде отчета либо в .pdf файле, либо ipython-тетрадке. \n",
47 | "4. Отчет должен содержать: нумерацию заданий и пунктов, которые вы выполнили, код решения, и понятное пошаговое описание того, что вы сделали. Отчет должен быть написан в академическом стиле, без излишнего использования сленга и с соблюдением норм русского языка.\n",
48 | "5. Не стоит копировать фрагменты лекций, статей и Википедии в ваш отчет.\n",
49 | "6. Отчеты, состоящие исключительно из кода, не будут проверены и будут автоматически оценены нулевой оценкой.\n",
50 | "7. Плагиат и любое недобросоветсное цитирование приводит к обнуление оценки. \n",
51 | "\n",
52 | "\n",
53 | "## Часть 1. [2 балла] Эксплоративный анализ \n",
54 | "1. Найдите топ 10 (по частоте) именованных сущностей каждого из 6 типов.\n",
55 | "2. Найдите топ 10 (по частоте) частотных триггеров событий. \n",
56 | "3. Кластеризуйте все уникальные триггеры событий, используя эмбеддинги слов и любой алгоритм кластеризации (например, агломеративный иерархический алгоритм кластеризации) и попробуйте проинтерпретировать кластеры: есть ли очевидные типы событий? \n",
57 | "\n",
58 | "[бонус] Визуализируйте полученные кластеры с помощью TSNE или UMAP\n",
59 | "\n",
60 | "[бонус] Постройте тематическую модель по корпусу и сравните кластеры тригеров и выделенные темы: есть ли схожие паттерны в тематической модели и в стурктуре кластеров?\n",
61 | "\n",
62 | "В следующих частях домашнего задания вам понадобится train-test-dev разбиение. Авторы статей предлагают следующую структуру разбиения: обучающее множество – 80 книг, валидационное – 10 книг, тестовое – 10 книг. Предложения из одного источника не должны попадать в разные сегменты разбиения. \n",
63 | "\n",
64 | "\n",
65 | "## Часть 2. [3 балла] Извлечение именованных сущностей\n",
66 | "1. Обучите стандартную модель для извлечения именованных сущностей, CNN-BiLSTM-CRF, для извлечения именованных *низкоуровневых именованных сущностей*, т.е. для самых коротких из вложенных сущностей. \n",
67 | "Модель устроена так: сверточная сеть на символах + эмбеддинги слов + двунаправленная LSTM сеть (модель последовательности) + CRF (глобальная нормализация).\n",
68 | "2. Замените часть модели на символах и словах (CNN + эмбеддинги словах) на ELMo и / или BERT. Должна получиться модель ELMo / BERT + BiLSTM + CRF. \n",
69 | "3. Замените модель последовательности (BiLSTM) на другой слой, например, на Transformer. Должна получиться модель CNN + Transformer + CRF. \n",
70 | "\n",
71 | "[бонус] Дообучите BERT для извлечения именованных сущностей.\n",
72 | "\n",
73 | "[бонус] Используйте модель для извлечения вложенных именованных сущностей [Ju et al., 2018]\n",
74 | "\n",
75 | "[бонус] Модифицируйте модель для извлечения вложенных именованных сущностей [Ju et al., 2018]: вместо эмбеддингов слов используйте ELMo и/или BERT. \n",
76 | "\n",
77 | "## Часть 3. [2 балла] Извлечение событий \n",
78 | "\n",
79 | "1. Используйте BiLSTM на эмбеддингах слов для извлечения триггеров событий. \n",
80 | "\n",
81 | "2. Замените часть модели на словах на ELMo и/или BERT. Должна получиться модель ELMo / BERT + BiLSTM.\n",
82 | "\n",
83 | "[бонус] Предобучите BiLSTM как языковую модель. Дообучите ее для извлечения триггеров. \n",
84 | "\n",
85 | "[бонус] Дообучите BERT для извлечения триггеров событий. \n",
86 | "\n",
87 | "## Часть 4. [2 балла] Одновременное извлечение именованных сущностей и событий \n",
88 | "1. Обучите модель для совместного извлечения именованных сущностей и триггеров событий. У модели должен быть общий энкодер (например, CNN + BiLSMT, ELMo + BiLSTM, BERT + BiLSTM) и два декодера: один отвечает за извлечение именнованных сущностей, другой отвечает за извлечение триггеров событий.\n",
89 | "\n",
90 | "[бонус] Добавьте в модель механизм внимания, так, как это покажется вам разумным.\n",
91 | "\n",
92 | "[бонус] Визуализируйте карты механизма внимания. \n",
93 | "\n",
94 | "## Часть 5. [1 балл] Итоги\n",
95 | "Напишите краткое резюме проделанной работы. Сравните результаты всех разработанных моделей. Что помогло вам в выполнении работы, чего не хватало?"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": null,
101 | "metadata": {},
102 | "outputs": [],
103 | "source": []
104 | }
105 | ],
106 | "metadata": {
107 | "kernelspec": {
108 | "display_name": "Python 3",
109 | "language": "python",
110 | "name": "python3"
111 | },
112 | "language_info": {
113 | "codemirror_mode": {
114 | "name": "ipython",
115 | "version": 3
116 | },
117 | "file_extension": ".py",
118 | "mimetype": "text/x-python",
119 | "name": "python",
120 | "nbconvert_exporter": "python",
121 | "pygments_lexer": "ipython3",
122 | "version": "3.6.0"
123 | }
124 | },
125 | "nbformat": 4,
126 | "nbformat_minor": 2
127 | }
128 |
--------------------------------------------------------------------------------
/HW/hw3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Домашнее задание 3\n",
8 | "## Yes/No Questions\n",
9 | "\n",
10 | "deadline: 3 декабря 2019, 23:59\n",
11 | "\n",
12 | "В этом домашнем задании вы будете работать с корпусом BoolQ. Корпус состоит из вопросов, предполагающих бинарный ответ (да / нет), абзацев из Википедии, содержащих ответ на вопрос, заголовка статьи, из которой извлечен абзац и непосредственно ответа (true / false).\n",
13 | "\n",
14 | "Корпус описан в статье:\n",
15 | "\n",
16 | "Christopher Clark, Kenton Lee, Ming-Wei Chang, Tom Kwiatkowski, Michael Collins, Kristina Toutanova\n",
17 | "BoolQ: Exploring the Surprising Difficulty of Natural Yes/No Questions\n",
18 | "\n",
19 | "https://arxiv.org/abs/1905.10044\n",
20 | "\n",
21 | "\n",
22 | "Корпус (train-dev split) доступен в репозитории проекта: https://github.com/google-research-datasets/boolean-questions\n",
23 | "\n",
24 | "Используйте для обучения train часть корпуса, для валидации и тестирования – dev часть. \n",
25 | "\n",
26 | "Каждый бонус пункт оцениватся в 1 балл. "
27 | ]
28 | },
29 | {
30 | "cell_type": "markdown",
31 | "metadata": {},
32 | "source": [
33 | "### Пример вопроса: \n",
34 | "question: is batman and robin a sequel to batman forever\n",
35 | "\n",
36 | "title: Batman & Robin (film)\n",
37 | "\n",
38 | "answer: true\n",
39 | "\n",
40 | "passage: With the box office success of Batman Forever in June 1995, Warner Bros. immediately commissioned a sequel. They hired director Joel Schumacher and writer Akiva Goldsman to reprise their duties the following August, and decided it was best to fast track production for a June 1997 target release date, which is a break from the usual 3-year gap between films. Schumacher wanted to homage both the broad camp style of the 1960s television series and the work of Dick Sprang. The storyline of Batman & Robin was conceived by Schumacher and Goldsman during pre-production on A Time to Kill. Portions of Mr. Freeze's back-story were based on the Batman: The Animated Series episode ''Heart of Ice'', written by Paul Dini."
41 | ]
42 | },
43 | {
44 | "cell_type": "markdown",
45 | "metadata": {},
46 | "source": [
47 | "## ПРАВИЛА\n",
48 | "1. Домашнее задание выполняется в группе до 3-х человек.\n",
49 | "2. Домашнее задание сдается через anytask, инвайты будут дополнительно высланы.\n",
50 | "3. Домашнее задание оформляется в виде отчета либо в .pdf файле, либо ipython-тетрадке. \n",
51 | "4. Отчет должен содержать: нумерацию заданий и пунктов, которые вы выполнили, код решения, и понятное пошаговое описание того, что вы сделали. Отчет должен быть написан в академическом стиле, без излишнего использования сленга и с соблюдением норм русского языка.\n",
52 | "5. Не стоит копировать фрагменты лекций, статей и Википедии в ваш отчет.\n",
53 | "6. Отчеты, состоящие исключительно из кода, не будут проверены и будут автоматически оценены нулевой оценкой.\n",
54 | "7. Плагиат и любое недобросоветсное цитирование приводит к обнуление оценки. "
55 | ]
56 | },
57 | {
58 | "cell_type": "markdown",
59 | "metadata": {},
60 | "source": [
61 | "## Часть 1. [1 балл] Эксплоративный анализ\n",
62 | "1. Посчитайте долю yes и no классов в корпусе\n",
63 | "2. Оцените среднюю длину вопроса\n",
64 | "3. Оцените среднюю длину параграфа\n",
65 | "4. Предположите, по каким эвристикам были собраны вопросы (или найдите ответ в статье). Продемонстриуйте, как эти эвристики повлияли на структуру корпуса. "
66 | ]
67 | },
68 | {
69 | "cell_type": "markdown",
70 | "metadata": {},
71 | "source": [
72 | "## Часть 2. [1 балл] Baseline\n",
73 | "1. Оцените accuracy точность совсем простого базового решения: присвоить каждой паре вопрос-ответ в dev части самый частый класс из train части\n",
74 | "2. Оцените accuracy чуть более сложного базового решения: fasttext на текстах, состоящих из склееных вопросов и абзацев (' '.join([question, passage]))\n",
75 | "\n",
76 | "Почему fasttext плохо справляется с этой задачей?"
77 | ]
78 | },
79 | {
80 | "cell_type": "markdown",
81 | "metadata": {},
82 | "source": [
83 | "## Часть 3. [1 балл] Используем эмбеддинги предложений\n",
84 | "1. Постройте BERT эмбеддинги вопроса и абзаца. Обучите логистическую регрессию на конкатенированных эмбеддингах вопроса и абзаца и оцените accuracy этого решения. \n",
85 | "\n",
86 | "[bonus] Используйте другие модели эмбеддингов, доступные, например, в библиотеке 🤗 Transformers. Какая модель эмбеддингов даст лучшие результаты?\n",
87 | "\n",
88 | "[bonus] Предложите метод аугментации данных и продемонстрируйте его эффективность. "
89 | ]
90 | },
91 | {
92 | "cell_type": "markdown",
93 | "metadata": {},
94 | "source": [
95 | "## Часть 3. [3 балла] DrQA-подобная архитектура\n",
96 | "\n",
97 | "Основана на статье: Reading Wikipedia to Answer Open-Domain Questions\n",
98 | "\n",
99 | "Danqi Chen, Adam Fisch, Jason Weston, Antoine Bordes\n",
100 | "\n",
101 | "https://arxiv.org/abs/1704.00051\n",
102 | "\n",
103 | "Архитектура DrQA предложена для задачи SQuAD, но легко может быть адаптирована к текущему заданию. Модель состоит из следующих блоков:\n",
104 | "1. Кодировщик абзаца [paragraph encoding] – LSTM, получаящая на вход вектора слов, состоящие из: \n",
105 | "* эмбеддинга слова (w2v или fasttext)\n",
106 | "* дополнительных признаков-индикаторов, кодирующих в виде one-hot векторов часть речи слова, является ли оно именованной сущностью или нет, встречается ли слово в вопросе или нет \n",
107 | "* выровненного эмбеддинга вопроса, получаемого с использованием soft attention между эмбеддингами слов из абзаца и эмбеддингом вопроса.\n",
108 | "\n",
109 | "$f_{align}(p_i) = \\sum_j a_{i,j} E(q_j)$, где $E(q_j)$ – эмбеддинг слова из вопроса. Формула для $a_{i,j}$ приведена в статье. \n",
110 | "\n",
111 | "2. Кодировщик вопроса [question encoding] – LSTM, получаящая на вход эмбеддинги слов из вопроса. Выход кодировщика: $q = \\sum_j b_j q_j$. Формула для $b_{j}$ приведена в статье. \n",
112 | "\n",
113 | "3. Слой предсказания. \n",
114 | "\n",
115 | "Предложите, как можно было модифицировать последний слой предсказания в архитектуре DrQA, с учетом того, что итоговое предсказание – это метка yes / no, предсказание которой проще, чем предсказание спана ответа для SQuAD.\n",
116 | "\n",
117 | "Оцените качество этой модели для решения задачи. \n",
118 | "\n",
119 | "[bonus] Замените входные эмбеддинги и все дополнительные признаки, используемые кодировщиками, на BERT эмбеддинги. Улучшит ли это качество результатов?"
120 | ]
121 | },
122 | {
123 | "cell_type": "markdown",
124 | "metadata": {},
125 | "source": [
126 | "## Часть 4. [3 балла] BiDAF-подобная архитектура\n",
127 | "\n",
128 | "Основана на статье: Bidirectional Attention Flow for Machine Comprehension\n",
129 | "\n",
130 | "Minjoon Seo, Aniruddha Kembhavi, Ali Farhadi, Hannaneh Hajishirzi\n",
131 | "\n",
132 | "https://arxiv.org/abs/1611.01603\n",
133 | "\n",
134 | "Архитектура BiDAF предложена для задачи SQuAD, но легко может быть адаптирована к текущему заданию. Модель состоит из следующих блоков:\n",
135 | "1. Кодировщик получает на вход два представления слова: эмбеддинг слова и полученное из CNN посимвольное представление слова. Кодировщики для вопроса и для параграфа одинаковы. \n",
136 | "2. Слой внимания (детальное описание приведено в статье, см. пункт Attention Flow Layer)\n",
137 | "3. Промежуточный слой, который получает на вход контекстуализированные эмбеддинги слов из параграфа, состоящие из трех частей (выход кодировщика параграфа, Query2Context (один вектор) и Context2Query (матрица) выравнивания\n",
138 | "\n",
139 | "4. Слой предсказания. \n",
140 | "\n",
141 | "Предложите, как можно было модифицировать последний слой предсказания в архитектуре BiDAF, с учетом того, что итоговое предсказание – это метка yes / no, предсказание которой проще, чем предсказание спана ответа для SQuAD.\n",
142 | "\n",
143 | "Оцените качество этой модели для решения задачи. \n",
144 | "\n",
145 | "[bonus] Замените входные эмбеддинги и все дополнительные признаки, используемые кодировщиками, на BERT эмбеддинги. Улучшит ли это качество результатов?"
146 | ]
147 | },
148 | {
149 | "cell_type": "markdown",
150 | "metadata": {},
151 | "source": [
152 | "Сравнение DrQA и BiDAF:\n",
153 | " \n",
154 | ""
155 | ]
156 | },
157 | {
158 | "cell_type": "markdown",
159 | "metadata": {},
160 | "source": [
161 | "## Часть 5. [1 балл] Итоги\n",
162 | "Напишите краткое резюме проделанной работы. Сравните результаты всех разработанных моделей. Что помогло вам в выполнении работы, чего не хватало?"
163 | ]
164 | }
165 | ],
166 | "metadata": {
167 | "kernelspec": {
168 | "display_name": "Python 3",
169 | "language": "python",
170 | "name": "python3"
171 | },
172 | "language_info": {
173 | "codemirror_mode": {
174 | "name": "ipython",
175 | "version": 3
176 | },
177 | "file_extension": ".py",
178 | "mimetype": "text/x-python",
179 | "name": "python",
180 | "nbconvert_exporter": "python",
181 | "pygments_lexer": "ipython3",
182 | "version": "3.6.8"
183 | }
184 | },
185 | "nbformat": 4,
186 | "nbformat_minor": 2
187 | }
188 |
--------------------------------------------------------------------------------
/HW/hw4.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Домашнее задание 4\n",
8 | "## Text Normalization \n",
9 | "\n",
10 | "deadline: 15 декабря 2019, 23:59\n",
11 | "\n",
12 | "В этом домашнем задании вы будете работать с корпусом соревнования по нормализации текстов на русском языке. \n",
13 | "\n",
14 | "Ссылка на соревнование:\n",
15 | "https://www.kaggle.com/c/text-normalization-challenge-russian-language\n",
16 | "\n",
17 | "Корпус (train-test split) доступен там же, на kaggle. Кроме того, kaggle проверяет результаты на тестовом множестве. Пример сабмита в файле: ru_sample_submission_2. \n",
18 | "\n",
19 | "Задача заключается в том, привести исходный текст (колонку before) в нормализованную форму (колонка after). Дополнительно известны классы токенов (колонка class), общее число классов – 15. В тестовом множестве классы токенов отсутствуют. \n",
20 | "\n",
21 | "Корпус состоит из предложений на русском языке и их нормализованных аналогов. Примеры продемонстрированы на kaggle."
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## ПРАВИЛА\n",
29 | "1. Домашнее задание выполняется в группе до 3-х человек.\n",
30 | "2. Домашнее задание сдается через anytask, инвайты будут дополнительно высланы.\n",
31 | "3. Домашнее задание оформляется в виде отчета либо в .pdf файле, либо ipython-тетрадке. \n",
32 | "4. Отчет должен содержать: нумерацию заданий и пунктов, которые вы выполнили, код решения, и понятное пошаговое описание того, что вы сделали. Отчет должен быть написан в академическом стиле, без излишнего использования сленга и с соблюдением норм русского языка.\n",
33 | "5. Не стоит копировать фрагменты лекций, статей и Википедии в ваш отчет.\n",
34 | "6. Отчеты, состоящие исключительно из кода, не будут проверены и будут автоматически оценены нулевой оценкой.\n",
35 | "7. Плагиат и любое недобросоветсное цитирование приводит к обнуление оценки. "
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "## Часть 1. [1 балл] Эксплоративный анализ\n",
43 | "\n",
44 | "1. Найдите примеры каждого класса и опишите, по какой логике проведена нормализация токенов разных классов. \n",
45 | "2. В каких случаях токены класса PLAIN подвергаются нормализации? \n",
46 | "3. Напишите правила для нормализации токенов класса ORDINAL. "
47 | ]
48 | },
49 | {
50 | "cell_type": "markdown",
51 | "metadata": {},
52 | "source": [
53 | "## Часть 2. [6 баллов] seq2seq архитектуры\n",
54 | "Имплементируйте несколько seq2seq архитектур. Энкодер получает на вход последовательность токенов before, декодер учится превращать их в токены after.\n",
55 | "Энкодер и декодер работают на уровне символов, эмбеддинги символов инициализируются случайно (по аналогии с работами, в которых предложены нейросетевые модели исправления опечаток).\n",
56 | "\n",
57 | "Эту часть задания рекомендуется выполнять с использованием allennlp (должно быть проще и удобнее).\n",
58 | "\n",
59 | "1. [3 балла] LSTM encoder + LSTM decoder + три механизма внимания: скалярное произведение, аддитивное внимание и мультипликативное внимание (см. лекцию 6, слайд \"подсчет весов attention\")\n",
60 | "2. [3 балла] Transformer\n",
61 | "\n",
62 | "Используя автопровереку kaggle, оцените, как влияют параметры архитектуры на качество задачи.\n",
63 | "\n",
64 | "[бонус] convolutional encoder + convolutional decoder\n",
65 | "\n",
66 | "[бонус] pyramid LSTM (размер l+1 слоя в два раз меньше размера l, i-тый вход l+1 слоя – конкатенация выходов 2i и 2i+1)"
67 | ]
68 | },
69 | {
70 | "cell_type": "markdown",
71 | "metadata": {},
72 | "source": [
73 | "## Часть 3. [2 балла] Дополнительные признаки\n",
74 | "Предложите и покажите, как можно было бы повысить качество нейросетевых моделей. Примерные варианты:\n",
75 | "1. ансамблирование нейронных сетей\n",
76 | "2. добавление морфологоческих признаков \n",
77 | "3. использование эмбеддингов слов \n"
78 | ]
79 | },
80 | {
81 | "cell_type": "markdown",
82 | "metadata": {},
83 | "source": [
84 | "## Часть 4. [1 балл] Итоги\n",
85 | "Напишите краткое резюме проделанной работы. Проведите анализ ошибок: когда модель ошибается? Можно ли скзаать, почему модель ошибается? Сравните результаты всех разработанных моделей. Что помогло вам в выполнении работы, чего не хватало?"
86 | ]
87 | }
88 | ],
89 | "metadata": {
90 | "kernelspec": {
91 | "display_name": "Python 3",
92 | "language": "python",
93 | "name": "python3"
94 | },
95 | "language_info": {
96 | "codemirror_mode": {
97 | "name": "ipython",
98 | "version": 3
99 | },
100 | "file_extension": ".py",
101 | "mimetype": "text/x-python",
102 | "name": "python",
103 | "nbconvert_exporter": "python",
104 | "pygments_lexer": "ipython3",
105 | "version": "3.7.4"
106 | }
107 | },
108 | "nbformat": 4,
109 | "nbformat_minor": 4
110 | }
111 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## NLP course @ FinTech HSE
2 |
3 | Week 1
4 | * Regex tutorial [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/1/1_regex.ipynb)
5 |
6 | * Preprocessing [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/1/1_preprocessing.ipynb)
7 |
8 | Week 2
9 | * Embeddings [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/2/2_embeddings.ipynb)
10 | * Quiz: https://forms.gle/DiS9rBskgxXxD6Hy6
11 |
12 | Week 3
13 | * Classification [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/3/3_classification.ipynb)
14 | * Quiz: https://forms.gle/mowmk9LgLG1yyLrh7
15 |
16 | Week 5
17 | * Topic Modelling [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/5/5_Keywords_and_Topic%20_Modelling.ipynb)
18 |
19 | Week 6
20 | * Seq2seq [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/6/6_seq2seq.ipynb)
21 |
22 | Week 7
23 | * AIJ Baseline [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/7/Baseline_AIJ.ipynb)
24 |
25 | Week 8
26 | * Syntax [](https://colab.research.google.com/github/PragmaticsLab/NLP-course-FinTech/blob/master/seminars/8/sem8_syntax.ipynb)
27 |
28 |
--------------------------------------------------------------------------------
/lectures/10_sumamrization_simplification.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/10_sumamrization_simplification.pdf
--------------------------------------------------------------------------------
/lectures/1_Intro.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/1_Intro.pdf
--------------------------------------------------------------------------------
/lectures/2_embeddings.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/2_embeddings.pdf
--------------------------------------------------------------------------------
/lectures/3_text-classification.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/3_text-classification.pdf
--------------------------------------------------------------------------------
/lectures/4_lm.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/4_lm.pdf
--------------------------------------------------------------------------------
/lectures/4_seq-model.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/4_seq-model.pdf
--------------------------------------------------------------------------------
/lectures/5_Anya_TM.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/5_Anya_TM.pdf
--------------------------------------------------------------------------------
/lectures/5_VSM.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/5_VSM.pdf
--------------------------------------------------------------------------------
/lectures/6_mt_attn_transformer.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/6_mt_attn_transformer.pdf
--------------------------------------------------------------------------------
/lectures/6_seq2seq.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/6_seq2seq.pdf
--------------------------------------------------------------------------------
/lectures/8_sesame_street.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/8_sesame_street.pdf
--------------------------------------------------------------------------------
/lectures/9_QA.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/lectures/9_QA.pdf
--------------------------------------------------------------------------------
/seminars/1/1_preprocessing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Инструменты для работы с языком "
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "... или зачем нужна предобработка.\n",
15 | "[](https://colab.research.google.com/drive/10_Aehfbxgr3fxXPgI1gM5BTU8yOy-Z4U)"
16 | ]
17 | },
18 | {
19 | "cell_type": "markdown",
20 | "metadata": {},
21 | "source": [
22 | "## Задача: классификация твитов по тональности\n",
23 | "\n",
24 | "У нас есть датасет из твитов, про каждый указано, как он эмоционально окрашен: положительно или отрицательно. Задача: предсказывать эмоциональную окраску.\n",
25 | "\n",
26 | "Классификацию по тональности используют в рекомендательных системах, чтобы понять, понравилось ли людям кафе, кино, etc.\n",
27 | "\n",
28 | "Скачиваем куски датасета ([источник](http://study.mokoron.com/)): [положительные](https://www.dropbox.com/s/fnpq3z4bcnoktiv/positive.csv?dl=0), [отрицательные](https://www.dropbox.com/s/r6u59ljhhjdg6j0/negative.csv)."
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": 1,
34 | "metadata": {},
35 | "outputs": [
36 | {
37 | "name": "stdout",
38 | "output_type": "stream",
39 | "text": [
40 | "--2019-09-02 00:49:13-- https://www.dropbox.com/s/fnpq3z4bcnoktiv/positive.csv\n",
41 | "Resolving www.dropbox.com (www.dropbox.com)... 162.125.70.1, 2620:100:6026:1::a27d:4601\n",
42 | "Connecting to www.dropbox.com (www.dropbox.com)|162.125.70.1|:443... connected.\n",
43 | "HTTP request sent, awaiting response... 301 Moved Permanently\n",
44 | "Location: /s/raw/fnpq3z4bcnoktiv/positive.csv [following]\n",
45 | "--2019-09-02 00:49:14-- https://www.dropbox.com/s/raw/fnpq3z4bcnoktiv/positive.csv\n",
46 | "Reusing existing connection to www.dropbox.com:443.\n",
47 | "HTTP request sent, awaiting response... 302 Found\n",
48 | "Location: https://uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com/cd/0/inline/AnwT7H4-uyTASGZ29VMT2RHYRhpDNf3WuM8qDk9NhZbSO7SotuSOlGSglzkKpVeYdUWiT-euhVeq055N0wT8ytXNptLgh86nZAwtog6jxewocA/file# [following]\n",
49 | "--2019-09-02 00:49:14-- https://uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com/cd/0/inline/AnwT7H4-uyTASGZ29VMT2RHYRhpDNf3WuM8qDk9NhZbSO7SotuSOlGSglzkKpVeYdUWiT-euhVeq055N0wT8ytXNptLgh86nZAwtog6jxewocA/file\n",
50 | "Resolving uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com (uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com)... 162.125.70.6, 2620:100:6026:6::a27d:4606\n",
51 | "Connecting to uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com (uc37649f91af1c6d1425b11f3390.dl.dropboxusercontent.com)|162.125.70.6|:443... connected.\n",
52 | "HTTP request sent, awaiting response... 200 OK\n",
53 | "Length: 26233379 (25M) [text/plain]\n",
54 | "Saving to: ‘positive.csv’\n",
55 | "\n",
56 | "positive.csv 100%[===================>] 25,02M 10,2MB/s in 2,5s \n",
57 | "\n",
58 | "2019-09-02 00:49:17 (10,2 MB/s) - ‘positive.csv’ saved [26233379/26233379]\n",
59 | "\n",
60 | "--2019-09-02 00:49:18-- https://www.dropbox.com/s/r6u59ljhhjdg6j0/negative.csv\n",
61 | "Resolving www.dropbox.com (www.dropbox.com)... 162.125.70.1, 2620:100:6026:1::a27d:4601\n",
62 | "Connecting to www.dropbox.com (www.dropbox.com)|162.125.70.1|:443... connected.\n",
63 | "HTTP request sent, awaiting response... 301 Moved Permanently\n",
64 | "Location: /s/raw/r6u59ljhhjdg6j0/negative.csv [following]\n",
65 | "--2019-09-02 00:49:18-- https://www.dropbox.com/s/raw/r6u59ljhhjdg6j0/negative.csv\n",
66 | "Reusing existing connection to www.dropbox.com:443.\n",
67 | "HTTP request sent, awaiting response... 302 Found\n",
68 | "Location: https://ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com/cd/0/inline/Anw2zr0ETFNThoiC6pm7hK5F7506E13XwPFhKHP7U8ztekf1bDgdauljxbPhy_jzQn9EMTO_LY9LR1iU87b4gCBYHrD9fFU1-M_RG6iWCfazSA/file# [following]\n",
69 | "--2019-09-02 00:49:18-- https://ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com/cd/0/inline/Anw2zr0ETFNThoiC6pm7hK5F7506E13XwPFhKHP7U8ztekf1bDgdauljxbPhy_jzQn9EMTO_LY9LR1iU87b4gCBYHrD9fFU1-M_RG6iWCfazSA/file\n",
70 | "Resolving ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com (ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com)... 162.125.70.6, 2620:100:6026:6::a27d:4606\n",
71 | "Connecting to ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com (ucf2e71715f7787ec44eab98fe74.dl.dropboxusercontent.com)|162.125.70.6|:443... connected.\n",
72 | "HTTP request sent, awaiting response... 200 OK\n",
73 | "Length: 24450101 (23M) [text/plain]\n",
74 | "Saving to: ‘negative.csv’\n",
75 | "\n",
76 | "negative.csv 100%[===================>] 23,32M 7,61MB/s in 3,1s \n",
77 | "\n",
78 | "2019-09-02 00:49:22 (7,61 MB/s) - ‘negative.csv’ saved [24450101/24450101]\n",
79 | "\n"
80 | ]
81 | }
82 | ],
83 | "source": [
84 | "# если у вас линукс / мак / collab или ещё какая-то среда, в которой работает wget, можно так:\n",
85 | "!wget https://www.dropbox.com/s/fnpq3z4bcnoktiv/positive.csv\n",
86 | "!wget https://www.dropbox.com/s/r6u59ljhhjdg6j0/negative.csv"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 2,
92 | "metadata": {},
93 | "outputs": [],
94 | "source": [
95 | "import pandas as pd\n",
96 | "import numpy as np\n",
97 | "from sklearn.metrics import *\n",
98 | "from sklearn.model_selection import train_test_split\n",
99 | "from sklearn.pipeline import Pipeline"
100 | ]
101 | },
102 | {
103 | "cell_type": "code",
104 | "execution_count": 3,
105 | "metadata": {},
106 | "outputs": [],
107 | "source": [
108 | "# считываем данные и заполняем общий датасет\n",
109 | "positive = pd.read_csv('positive.csv', sep=';', usecols=[3], names=['text'])\n",
110 | "positive['label'] = ['positive'] * len(positive)\n",
111 | "negative = pd.read_csv('negative.csv', sep=';', usecols=[3], names=['text'])\n",
112 | "negative['label'] = ['negative'] * len(negative)\n",
113 | "df = positive.append(negative)"
114 | ]
115 | },
116 | {
117 | "cell_type": "code",
118 | "execution_count": 4,
119 | "metadata": {},
120 | "outputs": [
121 | {
122 | "data": {
123 | "text/html": [
124 | "
\n",
125 | "\n",
138 | "
\n",
139 | " \n",
140 | " \n",
141 | " | \n",
142 | " text | \n",
143 | " label | \n",
144 | "
\n",
145 | " \n",
146 | " \n",
147 | " \n",
148 | " 111918 | \n",
149 | " Но не каждый хочет что то исправлять:( http://... | \n",
150 | " negative | \n",
151 | "
\n",
152 | " \n",
153 | " 111919 | \n",
154 | " скучаю так :-( только @taaannyaaa вправляет мо... | \n",
155 | " negative | \n",
156 | "
\n",
157 | " \n",
158 | " 111920 | \n",
159 | " Вот и в школу, в говно это идти уже надо( | \n",
160 | " negative | \n",
161 | "
\n",
162 | " \n",
163 | " 111921 | \n",
164 | " RT @_Them__: @LisaBeroud Тауриэль, не грусти :... | \n",
165 | " negative | \n",
166 | "
\n",
167 | " \n",
168 | " 111922 | \n",
169 | " Такси везет меня на работу. Раздумываю приплат... | \n",
170 | " negative | \n",
171 | "
\n",
172 | " \n",
173 | "
\n",
174 | "
"
175 | ],
176 | "text/plain": [
177 | " text label\n",
178 | "111918 Но не каждый хочет что то исправлять:( http://... negative\n",
179 | "111919 скучаю так :-( только @taaannyaaa вправляет мо... negative\n",
180 | "111920 Вот и в школу, в говно это идти уже надо( negative\n",
181 | "111921 RT @_Them__: @LisaBeroud Тауриэль, не грусти :... negative\n",
182 | "111922 Такси везет меня на работу. Раздумываю приплат... negative"
183 | ]
184 | },
185 | "execution_count": 4,
186 | "metadata": {},
187 | "output_type": "execute_result"
188 | }
189 | ],
190 | "source": [
191 | "df.tail()"
192 | ]
193 | },
194 | {
195 | "cell_type": "code",
196 | "execution_count": 5,
197 | "metadata": {},
198 | "outputs": [],
199 | "source": [
200 | "x_train, x_test, y_train, y_test = train_test_split(df.text, df.label)"
201 | ]
202 | },
203 | {
204 | "cell_type": "markdown",
205 | "metadata": {},
206 | "source": [
207 | "## Baseline: классификация необработанных n-грамм\n",
208 | "\n",
209 | "### Векторизаторы"
210 | ]
211 | },
212 | {
213 | "cell_type": "code",
214 | "execution_count": 12,
215 | "metadata": {},
216 | "outputs": [],
217 | "source": [
218 | "from sklearn.linear_model import LogisticRegression # можно заменить на любимый классификатор\n",
219 | "from sklearn.feature_extraction.text import CountVectorizer"
220 | ]
221 | },
222 | {
223 | "cell_type": "markdown",
224 | "metadata": {},
225 | "source": [
226 | "Что такое n-граммы:"
227 | ]
228 | },
229 | {
230 | "cell_type": "code",
231 | "execution_count": 7,
232 | "metadata": {},
233 | "outputs": [],
234 | "source": [
235 | "from nltk import ngrams"
236 | ]
237 | },
238 | {
239 | "cell_type": "code",
240 | "execution_count": 8,
241 | "metadata": {},
242 | "outputs": [
243 | {
244 | "data": {
245 | "text/plain": [
246 | "[('Если',), ('б',), ('мне',), ('платили',), ('каждый',), ('раз',)]"
247 | ]
248 | },
249 | "execution_count": 8,
250 | "metadata": {},
251 | "output_type": "execute_result"
252 | }
253 | ],
254 | "source": [
255 | "sent = 'Если б мне платили каждый раз'.split()\n",
256 | "list(ngrams(sent, 1)) # униграммы"
257 | ]
258 | },
259 | {
260 | "cell_type": "code",
261 | "execution_count": 9,
262 | "metadata": {},
263 | "outputs": [
264 | {
265 | "data": {
266 | "text/plain": [
267 | "[('Если', 'б'),\n",
268 | " ('б', 'мне'),\n",
269 | " ('мне', 'платили'),\n",
270 | " ('платили', 'каждый'),\n",
271 | " ('каждый', 'раз')]"
272 | ]
273 | },
274 | "execution_count": 9,
275 | "metadata": {},
276 | "output_type": "execute_result"
277 | }
278 | ],
279 | "source": [
280 | "list(ngrams(sent, 2)) # биграммы"
281 | ]
282 | },
283 | {
284 | "cell_type": "code",
285 | "execution_count": 10,
286 | "metadata": {},
287 | "outputs": [
288 | {
289 | "data": {
290 | "text/plain": [
291 | "[('Если', 'б', 'мне'),\n",
292 | " ('б', 'мне', 'платили'),\n",
293 | " ('мне', 'платили', 'каждый'),\n",
294 | " ('платили', 'каждый', 'раз')]"
295 | ]
296 | },
297 | "execution_count": 10,
298 | "metadata": {},
299 | "output_type": "execute_result"
300 | }
301 | ],
302 | "source": [
303 | "list(ngrams(sent, 3)) # триграммы"
304 | ]
305 | },
306 | {
307 | "cell_type": "code",
308 | "execution_count": 11,
309 | "metadata": {},
310 | "outputs": [
311 | {
312 | "data": {
313 | "text/plain": [
314 | "[('Если', 'б', 'мне', 'платили', 'каждый'),\n",
315 | " ('б', 'мне', 'платили', 'каждый', 'раз')]"
316 | ]
317 | },
318 | "execution_count": 11,
319 | "metadata": {},
320 | "output_type": "execute_result"
321 | }
322 | ],
323 | "source": [
324 | "list(ngrams(sent, 5)) # ... пентаграммы?"
325 | ]
326 | },
327 | {
328 | "cell_type": "markdown",
329 | "metadata": {},
330 | "source": [
331 | "Самый простой способ извлечь фичи из текстовых данных -- векторизаторы: `CountVectorizer` и `TfidfVectorizer`\n",
332 | "\n",
333 | "Объект `CountVectorizer` делает простую вещь:\n",
334 | "* строит для каждого документа (каждой пришедшей ему строки) вектор размерности `n`, где `n` -- количество слов или n-грам во всём корпусе\n",
335 | "* заполняет каждый i-тый элемент количеством вхождений слова в данный документ"
336 | ]
337 | },
338 | {
339 | "cell_type": "code",
340 | "execution_count": 13,
341 | "metadata": {},
342 | "outputs": [],
343 | "source": [
344 | "vec = CountVectorizer(ngram_range=(1, 1))\n",
345 | "bow = vec.fit_transform(x_train) # bow -- bag of words (мешок слов)"
346 | ]
347 | },
348 | {
349 | "cell_type": "markdown",
350 | "metadata": {},
351 | "source": [
352 | "ngram_range отвечает за то, какие n-граммы мы используем в качестве фичей:
\n",
353 | "ngram_range=(1, 1) -- униграммы
\n",
354 | "ngram_range=(3, 3) -- триграммы
\n",
355 | "ngram_range=(1, 3) -- униграммы, биграммы и триграммы.\n",
356 | "\n",
357 | "В vec.vocabulary_ лежит словарь: мэппинг слов к их индексам:"
358 | ]
359 | },
360 | {
361 | "cell_type": "code",
362 | "execution_count": 14,
363 | "metadata": {},
364 | "outputs": [
365 | {
366 | "data": {
367 | "text/plain": [
368 | "[('классным', 145519),\n",
369 | " ('адддд', 98275),\n",
370 | " ('vertu_dragon', 88391),\n",
371 | " ('покалечить', 187048),\n",
372 | " ('вмешался', 113304),\n",
373 | " ('неперевершений', 167001),\n",
374 | " ('ziqhqszh4i', 96622),\n",
375 | " ('налоговые', 163339),\n",
376 | " ('бытовухи', 109281),\n",
377 | " ('матово', 156797)]"
378 | ]
379 | },
380 | "execution_count": 14,
381 | "metadata": {},
382 | "output_type": "execute_result"
383 | }
384 | ],
385 | "source": [
386 | "list(vec.vocabulary_.items())[:10]"
387 | ]
388 | },
389 | {
390 | "cell_type": "code",
391 | "execution_count": 15,
392 | "metadata": {},
393 | "outputs": [
394 | {
395 | "data": {
396 | "text/plain": [
397 | "LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
398 | " intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n",
399 | " penalty='l2', random_state=42, solver='liblinear', tol=0.0001,\n",
400 | " verbose=0, warm_start=False)"
401 | ]
402 | },
403 | "execution_count": 15,
404 | "metadata": {},
405 | "output_type": "execute_result"
406 | }
407 | ],
408 | "source": [
409 | "clf = LogisticRegression(random_state=42)\n",
410 | "clf.fit(bow, y_train)"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 16,
416 | "metadata": {},
417 | "outputs": [
418 | {
419 | "name": "stdout",
420 | "output_type": "stream",
421 | "text": [
422 | " precision recall f1-score support\n",
423 | "\n",
424 | " negative 0.76 0.75 0.76 28317\n",
425 | " positive 0.76 0.76 0.76 28392\n",
426 | "\n",
427 | "avg / total 0.76 0.76 0.76 56709\n",
428 | "\n"
429 | ]
430 | }
431 | ],
432 | "source": [
433 | "pred = clf.predict(vec.transform(x_test))\n",
434 | "print(classification_report(pred, y_test))"
435 | ]
436 | },
437 | {
438 | "cell_type": "markdown",
439 | "metadata": {},
440 | "source": [
441 | "Попробуем сделать то же самое для триграмм:"
442 | ]
443 | },
444 | {
445 | "cell_type": "code",
446 | "execution_count": 20,
447 | "metadata": {},
448 | "outputs": [
449 | {
450 | "name": "stdout",
451 | "output_type": "stream",
452 | "text": [
453 | " precision recall f1-score support\n",
454 | "\n",
455 | " negative 0.46 0.71 0.56 18138\n",
456 | " positive 0.82 0.61 0.70 38571\n",
457 | "\n",
458 | "avg / total 0.71 0.64 0.65 56709\n",
459 | "\n"
460 | ]
461 | }
462 | ],
463 | "source": [
464 | "vec = CountVectorizer(ngram_range=(3, 3))\n",
465 | "bow = vec.fit_transform(x_train)\n",
466 | "clf = LogisticRegression(random_state=42)\n",
467 | "clf.fit(bow, y_train)\n",
468 | "pred = clf.predict(vec.transform(x_test))\n",
469 | "print(classification_report(pred, y_test))"
470 | ]
471 | },
472 | {
473 | "cell_type": "markdown",
474 | "metadata": {},
475 | "source": [
476 | "(как вы думаете, почему в результатах теперь такой разброс по сравнению с униграммами?)"
477 | ]
478 | },
479 | {
480 | "cell_type": "markdown",
481 | "metadata": {},
482 | "source": [
483 | "## TF-IDF векторизация"
484 | ]
485 | },
486 | {
487 | "cell_type": "markdown",
488 | "metadata": {},
489 | "source": [
490 | "`TfidfVectorizer` делает то же, что и `CountVectorizer`, но в качестве значений – tf-idf каждого слова.\n",
491 | "\n",
492 | "Как считается tf-idf:\n",
493 | "\n",
494 | "TF (term frequency) – относительная частотность слова в документе:\n",
495 | "$$ TF(t,d) = \\frac{n_t}{\\sum_k n_k} $$\n",
496 | "\n",
497 | "`t` -- слово (term), `d` -- документ, $n_t$ -- количество вхождений слова, $n_k$ -- количество вхождений остальных слов\n",
498 | "\n",
499 | "IDF (inverse document frequency) – обратная частота документов, в которых есть это слово:\n",
500 | "$$ IDF(t, D) = \\mbox{log} \\frac{|D|}{|{d : t \\in d}|} $$\n",
501 | "\n",
502 | "`t` -- слово (term), `D` -- коллекция документов\n",
503 | "\n",
504 | "Перемножаем их:\n",
505 | "$$TFIDF_(t,d,D) = TF(t,d) \\times IDF(i, D)$$\n",
506 | "\n",
507 | "Сакральный смысл – если слово часто встречается в одном документе, но в целом по корпусу встречается в небольшом \n",
508 | "количестве документов, у него высокий TF-IDF."
509 | ]
510 | },
511 | {
512 | "cell_type": "code",
513 | "execution_count": 21,
514 | "metadata": {},
515 | "outputs": [],
516 | "source": [
517 | "from sklearn.feature_extraction.text import TfidfVectorizer"
518 | ]
519 | },
520 | {
521 | "cell_type": "code",
522 | "execution_count": 22,
523 | "metadata": {},
524 | "outputs": [
525 | {
526 | "name": "stdout",
527 | "output_type": "stream",
528 | "text": [
529 | " precision recall f1-score support\n",
530 | "\n",
531 | " negative 0.73 0.76 0.74 26717\n",
532 | " positive 0.78 0.74 0.76 29992\n",
533 | "\n",
534 | "avg / total 0.75 0.75 0.75 56709\n",
535 | "\n"
536 | ]
537 | }
538 | ],
539 | "source": [
540 | "vec = TfidfVectorizer(ngram_range=(1, 1))\n",
541 | "bow = vec.fit_transform(x_train)\n",
542 | "clf = LogisticRegression(random_state=42)\n",
543 | "clf.fit(bow, y_train)\n",
544 | "pred = clf.predict(vec.transform(x_test))\n",
545 | "print(classification_report(pred, y_test))"
546 | ]
547 | },
548 | {
549 | "cell_type": "markdown",
550 | "metadata": {},
551 | "source": [
552 | "В этот раз получилось хуже :( Вернёмся к `CountVectorizer`."
553 | ]
554 | },
555 | {
556 | "cell_type": "markdown",
557 | "metadata": {},
558 | "source": [
559 | "## Токенизация\n",
560 | "\n",
561 | "Токенизировать -- значит, поделить текст на слова, или *токены*.\n",
562 | "\n",
563 | "Самый наивный способ токенизировать текст -- разделить с помощью `split`. Но `split` упускает очень много всего, например, банально не отделяет пунктуацию от слов. Кроме этого, есть ещё много менее тривиальных проблем. Поэтому лучше использовать готовые токенизаторы."
564 | ]
565 | },
566 | {
567 | "cell_type": "code",
568 | "execution_count": 23,
569 | "metadata": {},
570 | "outputs": [],
571 | "source": [
572 | "from nltk.tokenize import word_tokenize"
573 | ]
574 | },
575 | {
576 | "cell_type": "code",
577 | "execution_count": 24,
578 | "metadata": {},
579 | "outputs": [
580 | {
581 | "data": {
582 | "text/plain": [
583 | "['Но', 'не', 'каждый', 'хочет', 'что-то', 'исправлять', ':', '(']"
584 | ]
585 | },
586 | "execution_count": 24,
587 | "metadata": {},
588 | "output_type": "execute_result"
589 | }
590 | ],
591 | "source": [
592 | "example = 'Но не каждый хочет что-то исправлять:('\n",
593 | "word_tokenize(example)"
594 | ]
595 | },
596 | {
597 | "cell_type": "markdown",
598 | "metadata": {},
599 | "source": [
600 | "В nltk вообще есть довольно много токенизаторов:"
601 | ]
602 | },
603 | {
604 | "cell_type": "code",
605 | "execution_count": 25,
606 | "metadata": {},
607 | "outputs": [
608 | {
609 | "data": {
610 | "text/plain": [
611 | "['BlanklineTokenizer',\n",
612 | " 'LineTokenizer',\n",
613 | " 'MWETokenizer',\n",
614 | " 'PunktSentenceTokenizer',\n",
615 | " 'RegexpTokenizer',\n",
616 | " 'ReppTokenizer',\n",
617 | " 'SExprTokenizer',\n",
618 | " 'SpaceTokenizer',\n",
619 | " 'StanfordSegmenter',\n",
620 | " 'TabTokenizer',\n",
621 | " 'TextTilingTokenizer',\n",
622 | " 'ToktokTokenizer',\n",
623 | " 'TreebankWordTokenizer',\n",
624 | " 'TweetTokenizer',\n",
625 | " 'WhitespaceTokenizer',\n",
626 | " 'WordPunctTokenizer']"
627 | ]
628 | },
629 | "execution_count": 25,
630 | "metadata": {},
631 | "output_type": "execute_result"
632 | }
633 | ],
634 | "source": [
635 | "from nltk import tokenize\n",
636 | "dir(tokenize)[:16]"
637 | ]
638 | },
639 | {
640 | "cell_type": "markdown",
641 | "metadata": {},
642 | "source": [
643 | "Они умеют выдавать индексы начала и конца каждого токена:"
644 | ]
645 | },
646 | {
647 | "cell_type": "code",
648 | "execution_count": 26,
649 | "metadata": {},
650 | "outputs": [
651 | {
652 | "data": {
653 | "text/plain": [
654 | "[(0, 2), (3, 5), (6, 12), (13, 18), (19, 25), (26, 38)]"
655 | ]
656 | },
657 | "execution_count": 26,
658 | "metadata": {},
659 | "output_type": "execute_result"
660 | }
661 | ],
662 | "source": [
663 | "wh_tok = tokenize.WhitespaceTokenizer()\n",
664 | "list(wh_tok.span_tokenize(example))"
665 | ]
666 | },
667 | {
668 | "cell_type": "markdown",
669 | "metadata": {},
670 | "source": [
671 | "(если вам было интересно, зачем вообще включать в модуль токенизатор, который работает как `.split()` :))\n",
672 | "\n",
673 | "Некторые токенизаторы ведут себя специфично:"
674 | ]
675 | },
676 | {
677 | "cell_type": "code",
678 | "execution_count": 27,
679 | "metadata": {},
680 | "outputs": [
681 | {
682 | "data": {
683 | "text/plain": [
684 | "['do', \"n't\", 'stop', 'me']"
685 | ]
686 | },
687 | "execution_count": 27,
688 | "metadata": {},
689 | "output_type": "execute_result"
690 | }
691 | ],
692 | "source": [
693 | "tokenize.TreebankWordTokenizer().tokenize(\"don't stop me\")"
694 | ]
695 | },
696 | {
697 | "cell_type": "markdown",
698 | "metadata": {},
699 | "source": [
700 | "Для некоторых задач это может быть полезно.\n",
701 | "\n",
702 | "А некоторые -- вообще не для текста на естественном языке (не очень понятно, зачем это в nltk :)):"
703 | ]
704 | },
705 | {
706 | "cell_type": "code",
707 | "execution_count": 28,
708 | "metadata": {},
709 | "outputs": [
710 | {
711 | "data": {
712 | "text/plain": [
713 | "['(a (b c))', 'd', 'e', '(f)']"
714 | ]
715 | },
716 | "execution_count": 28,
717 | "metadata": {},
718 | "output_type": "execute_result"
719 | }
720 | ],
721 | "source": [
722 | "tokenize.SExprTokenizer().tokenize(\"(a (b c)) d e (f)\")"
723 | ]
724 | },
725 | {
726 | "cell_type": "markdown",
727 | "metadata": {},
728 | "source": [
729 | "## Стоп-слова и пунктуация\n",
730 | "\n",
731 | "*Стоп-слова* -- это слова, которые часто встречаются практически в любом тексте и ничего интересного не говорят о конретном документе, то есть играют роль шума. Поэтому их принято убирать. По той же причине убирают и пунктуацию."
732 | ]
733 | },
734 | {
735 | "cell_type": "code",
736 | "execution_count": 29,
737 | "metadata": {},
738 | "outputs": [
739 | {
740 | "name": "stdout",
741 | "output_type": "stream",
742 | "text": [
743 | "['и', 'в', 'во', 'не', 'что', 'он', 'на', 'я', 'с', 'со', 'как', 'а', 'то', 'все', 'она', 'так', 'его', 'но', 'да', 'ты', 'к', 'у', 'же', 'вы', 'за', 'бы', 'по', 'только', 'ее', 'мне', 'было', 'вот', 'от', 'меня', 'еще', 'нет', 'о', 'из', 'ему', 'теперь', 'когда', 'даже', 'ну', 'вдруг', 'ли', 'если', 'уже', 'или', 'ни', 'быть', 'был', 'него', 'до', 'вас', 'нибудь', 'опять', 'уж', 'вам', 'ведь', 'там', 'потом', 'себя', 'ничего', 'ей', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней', 'для', 'мы', 'тебя', 'их', 'чем', 'была', 'сам', 'чтоб', 'без', 'будто', 'чего', 'раз', 'тоже', 'себе', 'под', 'будет', 'ж', 'тогда', 'кто', 'этот', 'того', 'потому', 'этого', 'какой', 'совсем', 'ним', 'здесь', 'этом', 'один', 'почти', 'мой', 'тем', 'чтобы', 'нее', 'сейчас', 'были', 'куда', 'зачем', 'всех', 'никогда', 'можно', 'при', 'наконец', 'два', 'об', 'другой', 'хоть', 'после', 'над', 'больше', 'тот', 'через', 'эти', 'нас', 'про', 'всего', 'них', 'какая', 'много', 'разве', 'три', 'эту', 'моя', 'впрочем', 'хорошо', 'свою', 'этой', 'перед', 'иногда', 'лучше', 'чуть', 'том', 'нельзя', 'такой', 'им', 'более', 'всегда', 'конечно', 'всю', 'между']\n"
744 | ]
745 | }
746 | ],
747 | "source": [
748 | "# у вас здесь, вероятно, выскочит ошибка и надо будет загрузить стоп слова (в тексте ошибки написано, как)\n",
749 | "from nltk.corpus import stopwords\n",
750 | "print(stopwords.words('russian'))"
751 | ]
752 | },
753 | {
754 | "cell_type": "code",
755 | "execution_count": 30,
756 | "metadata": {},
757 | "outputs": [
758 | {
759 | "data": {
760 | "text/plain": [
761 | "'!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'"
762 | ]
763 | },
764 | "execution_count": 30,
765 | "metadata": {},
766 | "output_type": "execute_result"
767 | }
768 | ],
769 | "source": [
770 | "from string import punctuation\n",
771 | "punctuation"
772 | ]
773 | },
774 | {
775 | "cell_type": "code",
776 | "execution_count": 31,
777 | "metadata": {},
778 | "outputs": [],
779 | "source": [
780 | "noise = stopwords.words('russian') + list(punctuation)"
781 | ]
782 | },
783 | {
784 | "cell_type": "markdown",
785 | "metadata": {},
786 | "source": [
787 | "В векторизаторах за стоп-слова, логичным образом, отвечает аргумент `stop_words`."
788 | ]
789 | },
790 | {
791 | "cell_type": "code",
792 | "execution_count": 32,
793 | "metadata": {},
794 | "outputs": [
795 | {
796 | "name": "stdout",
797 | "output_type": "stream",
798 | "text": [
799 | " precision recall f1-score support\n",
800 | "\n",
801 | " negative 0.80 0.76 0.78 29325\n",
802 | " positive 0.76 0.79 0.77 27384\n",
803 | "\n",
804 | "avg / total 0.78 0.78 0.78 56709\n",
805 | "\n"
806 | ]
807 | }
808 | ],
809 | "source": [
810 | "vec = CountVectorizer(ngram_range=(1, 1), tokenizer=word_tokenize, stop_words=noise)\n",
811 | "bow = vec.fit_transform(x_train)\n",
812 | "clf = LogisticRegression(random_state=42)\n",
813 | "clf.fit(bow, y_train)\n",
814 | "pred = clf.predict(vec.transform(x_test))\n",
815 | "print(classification_report(pred, y_test))"
816 | ]
817 | },
818 | {
819 | "cell_type": "markdown",
820 | "metadata": {},
821 | "source": [
822 | "Получилось чууть лучше. Что ещё можно сделать?"
823 | ]
824 | },
825 | {
826 | "cell_type": "markdown",
827 | "metadata": {},
828 | "source": [
829 | "## Лемматизация\n",
830 | "\n",
831 | "Лемматизация – это сведение разных форм одного слова к начальной форме – *лемме*. Почему это хорошо?\n",
832 | "* Во-первых, мы хотим рассматривать как отдельную фичу каждое *слово*, а не каждую его отдельную форму.\n",
833 | "* Во-вторых, некоторые стоп-слова стоят только в начальной форме, и без лематизации выкидываем мы только её.\n",
834 | "\n",
835 | "Для русского есть два хороших лемматизатора: mystem и pymorphy:\n",
836 | "\n",
837 | "### [Mystem](https://tech.yandex.ru/mystem/)\n",
838 | "Как с ним работать:\n",
839 | "* можно скачать mystem и запускать [из терминала с разными параметрами](https://tech.yandex.ru/mystem/doc/)\n",
840 | "* [pymystem3](https://pythonhosted.org/pymystem3/pymystem3.html) - обертка для питона, работает медленнее, но это удобно"
841 | ]
842 | },
843 | {
844 | "cell_type": "code",
845 | "execution_count": 33,
846 | "metadata": {},
847 | "outputs": [],
848 | "source": [
849 | "from pymystem3 import Mystem\n",
850 | "mystem_analyzer = Mystem()"
851 | ]
852 | },
853 | {
854 | "cell_type": "markdown",
855 | "metadata": {},
856 | "source": [
857 | "Мы инициализировали Mystem c дефолтными параметрами. А вообще параметры есть такие:\n",
858 | "* mystem_bin - путь к `mystem`, если их несколько\n",
859 | "* grammar_info - нужна ли грамматическая информация или только леммы (по дефолту нужна)\n",
860 | "* disambiguation - нужно ли снятие омонимии - дизамбигуация (по дефолту нужна)\n",
861 | "* entire_input - нужно ли сохранять в выводе все (пробелы всякие, например), или можно выкинуть (по дефолту оставляется все)\n",
862 | "\n",
863 | "Методы Mystem принимают строку, токенизатор вшит внутри. Можно, конечно, и пословно анализировать, но тогда он не сможет учитывать контекст.\n",
864 | "\n",
865 | "Можно просто лемматизировать текст:"
866 | ]
867 | },
868 | {
869 | "cell_type": "code",
870 | "execution_count": 34,
871 | "metadata": {},
872 | "outputs": [
873 | {
874 | "name": "stdout",
875 | "output_type": "stream",
876 | "text": [
877 | "['но', ' ', 'не', ' ', 'каждый', ' ', 'хотеть', ' ', 'что-то', ' ', 'исправлять', ':(\\n']\n"
878 | ]
879 | }
880 | ],
881 | "source": [
882 | "print(mystem_analyzer.lemmatize(example))"
883 | ]
884 | },
885 | {
886 | "cell_type": "markdown",
887 | "metadata": {},
888 | "source": [
889 | "А можно получить грамматическую информацию:"
890 | ]
891 | },
892 | {
893 | "cell_type": "code",
894 | "execution_count": 35,
895 | "metadata": {},
896 | "outputs": [
897 | {
898 | "data": {
899 | "text/plain": [
900 | "[{'analysis': [{'gr': 'CONJ=', 'lex': 'но'}], 'text': 'Но'},\n",
901 | " {'text': ' '},\n",
902 | " {'analysis': [{'gr': 'PART=', 'lex': 'не'}], 'text': 'не'},\n",
903 | " {'text': ' '},\n",
904 | " {'analysis': [{'gr': 'APRO=(вин,ед,муж,неод|им,ед,муж)', 'lex': 'каждый'}],\n",
905 | " 'text': 'каждый'},\n",
906 | " {'text': ' '},\n",
907 | " {'analysis': [{'gr': 'V,несов,пе=непрош,ед,изъяв,3-л', 'lex': 'хотеть'}],\n",
908 | " 'text': 'хочет'},\n",
909 | " {'text': ' '},\n",
910 | " {'analysis': [{'gr': 'SPRO,ед,сред,неод=(вин|им)', 'lex': 'что-то'}],\n",
911 | " 'text': 'что-то'},\n",
912 | " {'text': ' '},\n",
913 | " {'analysis': [{'gr': 'V,пе=инф,несов', 'lex': 'исправлять'}],\n",
914 | " 'text': 'исправлять'},\n",
915 | " {'text': ':(\\n'}]"
916 | ]
917 | },
918 | "execution_count": 35,
919 | "metadata": {},
920 | "output_type": "execute_result"
921 | }
922 | ],
923 | "source": [
924 | "mystem_analyzer.analyze(example)"
925 | ]
926 | },
927 | {
928 | "cell_type": "markdown",
929 | "metadata": {},
930 | "source": [
931 | "Давайте терепь лемматизатор майстема в качестве токенизатора."
932 | ]
933 | },
934 | {
935 | "cell_type": "code",
936 | "execution_count": 36,
937 | "metadata": {},
938 | "outputs": [],
939 | "source": [
940 | "import re\n",
941 | "def my_preproc(text):\n",
942 | " text = re.sub('[{}]'.format(punctuation), '', text)\n",
943 | " text = mystem_analyzer.lemmatize(text)\n",
944 | " return [word for word in text if word not in stopwords.words('russian') + [' ', '\\n']]"
945 | ]
946 | },
947 | {
948 | "cell_type": "code",
949 | "execution_count": null,
950 | "metadata": {},
951 | "outputs": [],
952 | "source": [
953 | "vec = CountVectorizer(ngram_range=(1, 1), tokenizer=my_preproc)\n",
954 | "bow = vec.fit_transform(x_train)\n",
955 | "clf = LogisticRegression(random_state=42)\n",
956 | "clf.fit(bow, y_train)\n",
957 | "pred = clf.predict(vec.transform(x_test))\n",
958 | "print(classification_report(pred, y_test))"
959 | ]
960 | },
961 | {
962 | "cell_type": "markdown",
963 | "metadata": {},
964 | "source": [
965 | "### [Pymorphy](http://pymorphy2.readthedocs.io/en/latest/)\n",
966 | "Это модуль на питоне, довольно быстрый и с кучей функций."
967 | ]
968 | },
969 | {
970 | "cell_type": "code",
971 | "execution_count": 69,
972 | "metadata": {},
973 | "outputs": [],
974 | "source": [
975 | "from pymorphy2 import MorphAnalyzer\n",
976 | "pymorphy2_analyzer = MorphAnalyzer()"
977 | ]
978 | },
979 | {
980 | "cell_type": "markdown",
981 | "metadata": {},
982 | "source": [
983 | "pymorphy2 работает с отдельными словами. Если дать ему на вход предложение - он его просто не лемматизирует, т.к. не понимает"
984 | ]
985 | },
986 | {
987 | "cell_type": "code",
988 | "execution_count": 72,
989 | "metadata": {},
990 | "outputs": [
991 | {
992 | "data": {
993 | "text/plain": [
994 | "[Parse(word='платили', tag=OpencorporaTag('VERB,impf,tran plur,past,indc'), normal_form='платить', score=1.0, methods_stack=((, 'платили', 2368, 10),))]"
995 | ]
996 | },
997 | "execution_count": 72,
998 | "metadata": {},
999 | "output_type": "execute_result"
1000 | }
1001 | ],
1002 | "source": [
1003 | "ana = pymorphy2_analyzer.parse(sent[3])\n",
1004 | "ana"
1005 | ]
1006 | },
1007 | {
1008 | "cell_type": "code",
1009 | "execution_count": 82,
1010 | "metadata": {},
1011 | "outputs": [
1012 | {
1013 | "data": {
1014 | "text/plain": [
1015 | "'платить'"
1016 | ]
1017 | },
1018 | "execution_count": 82,
1019 | "metadata": {},
1020 | "output_type": "execute_result"
1021 | }
1022 | ],
1023 | "source": [
1024 | "ana[0].normal_form"
1025 | ]
1026 | },
1027 | {
1028 | "cell_type": "markdown",
1029 | "metadata": {},
1030 | "source": [
1031 | "А теперь напишите аналогичную функцию для лемматизации с pymorphy2:"
1032 | ]
1033 | },
1034 | {
1035 | "cell_type": "code",
1036 | "execution_count": null,
1037 | "metadata": {},
1038 | "outputs": [],
1039 | "source": []
1040 | },
1041 | {
1042 | "cell_type": "markdown",
1043 | "metadata": {},
1044 | "source": [
1045 | "Что будет, если использовать её в качестве препроцессора? "
1046 | ]
1047 | },
1048 | {
1049 | "cell_type": "code",
1050 | "execution_count": null,
1051 | "metadata": {},
1052 | "outputs": [],
1053 | "source": []
1054 | },
1055 | {
1056 | "cell_type": "markdown",
1057 | "metadata": {},
1058 | "source": [
1059 | "### mystem vs. pymorphy\n",
1060 | "\n",
1061 | "1) *Мы надеемся, что вы пользуетесь линуксом*, но mystem работает невероятно медленно под windows на больших текстах.\n",
1062 | "\n",
1063 | "2) *Снятие омонимии*. Mystem умеет снимать омонимию по контексту (хотя не всегда преуспевает), pymorphy2 берет на вход одно слово и соответственно вообще не умеет дизамбигуировать по контексту:"
1064 | ]
1065 | },
1066 | {
1067 | "cell_type": "code",
1068 | "execution_count": 24,
1069 | "metadata": {},
1070 | "outputs": [
1071 | {
1072 | "name": "stdout",
1073 | "output_type": "stream",
1074 | "text": [
1075 | "{'text': 'сорока', 'analysis': [{'gr': 'NUM=(пр|дат|род|твор)', 'lex': 'сорок'}]}\n",
1076 | "{'text': 'Сорока', 'analysis': [{'gr': 'S,жен,од=им,ед', 'lex': 'сорока'}]}\n"
1077 | ]
1078 | }
1079 | ],
1080 | "source": [
1081 | "homonym1 = 'За время обучения я прослушал больше сорока курсов.'\n",
1082 | "homonym2 = 'Сорока своровала блестящее украшение со стола.'\n",
1083 | "mystem_analyzer = Mystem() # инициализирую объект с дефолтными параметрами\n",
1084 | "\n",
1085 | "print(mystem_analyzer.analyze(homonym1)[-5])\n",
1086 | "print(mystem_analyzer.analyze(homonym2)[0])"
1087 | ]
1088 | },
1089 | {
1090 | "cell_type": "code",
1091 | "execution_count": null,
1092 | "metadata": {},
1093 | "outputs": [],
1094 | "source": []
1095 | },
1096 | {
1097 | "cell_type": "markdown",
1098 | "metadata": {},
1099 | "source": [
1100 | "## Словарь, закон Ципфа и закон Хипса"
1101 | ]
1102 | },
1103 | {
1104 | "cell_type": "markdown",
1105 | "metadata": {},
1106 | "source": [
1107 | "Закон Ципфа -- эмпирическая закономерность: если все слова корпуса текста упорядочить по убыванию частоты их использования, то частота n-го слова в таком списке окажется приблизительно обратно пропорциональной его порядковому номеру n. Иными словами, частотность слов убывает очень быстро."
1108 | ]
1109 | },
1110 | {
1111 | "cell_type": "code",
1112 | "execution_count": 15,
1113 | "metadata": {},
1114 | "outputs": [],
1115 | "source": [
1116 | "from collections import Counter"
1117 | ]
1118 | },
1119 | {
1120 | "cell_type": "code",
1121 | "execution_count": 25,
1122 | "metadata": {},
1123 | "outputs": [
1124 | {
1125 | "name": "stdout",
1126 | "output_type": "stream",
1127 | "text": [
1128 | "2859142\n"
1129 | ]
1130 | },
1131 | {
1132 | "data": {
1133 | "text/plain": [
1134 | "['first_timee', 'хоть', 'я', 'и', 'школота', 'но', 'поверь', 'у', 'нас', 'то']"
1135 | ]
1136 | },
1137 | "execution_count": 25,
1138 | "metadata": {},
1139 | "output_type": "execute_result"
1140 | }
1141 | ],
1142 | "source": [
1143 | "corpus = [token for tweet in df.text for token in word_tokenize(tweet) if token not in punctuation]\n",
1144 | "print(len(corpus))\n",
1145 | "corpus[:10]"
1146 | ]
1147 | },
1148 | {
1149 | "cell_type": "code",
1150 | "execution_count": 26,
1151 | "metadata": {},
1152 | "outputs": [
1153 | {
1154 | "data": {
1155 | "text/plain": [
1156 | "[('не', 69267),\n",
1157 | " ('и', 54916),\n",
1158 | " ('в', 52853),\n",
1159 | " ('я', 52506),\n",
1160 | " ('RT', 38070),\n",
1161 | " ('на', 35715),\n",
1162 | " ('http', 32992),\n",
1163 | " ('что', 31472),\n",
1164 | " ('...', 28773),\n",
1165 | " ('с', 27176)]"
1166 | ]
1167 | },
1168 | "execution_count": 26,
1169 | "metadata": {},
1170 | "output_type": "execute_result"
1171 | }
1172 | ],
1173 | "source": [
1174 | "freq_dict = Counter(corpus)\n",
1175 | "freq_dict_sorted= sorted(freq_dict.items(), key=lambda x: -x[1])\n",
1176 | "list(freq_dict_sorted)[:10]"
1177 | ]
1178 | },
1179 | {
1180 | "cell_type": "code",
1181 | "execution_count": 31,
1182 | "metadata": {},
1183 | "outputs": [
1184 | {
1185 | "data": {
1186 | "image/png": "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\n",
1187 | "text/plain": [
1188 | ""
1189 | ]
1190 | },
1191 | "metadata": {},
1192 | "output_type": "display_data"
1193 | }
1194 | ],
1195 | "source": [
1196 | "import matplotlib.pyplot as plt\n",
1197 | "%matplotlib inline\n",
1198 | "first_100_freqs = [freq for word, freq in freq_dict_sorted[:100]]\n",
1199 | "plt.plot(first_100_freqs)\n",
1200 | "plt.show()"
1201 | ]
1202 | },
1203 | {
1204 | "cell_type": "markdown",
1205 | "metadata": {},
1206 | "source": [
1207 | "Закон Хипса -- обратная сторона закона Ципфа. Он описывает, что чем больше корпус, тем меньше новых слов добавляется с добавлением новых текстов. В какой-то момент корпус насыщается."
1208 | ]
1209 | },
1210 | {
1211 | "cell_type": "markdown",
1212 | "metadata": {},
1213 | "source": [
1214 | "## О важности эксплоративного анализа\n",
1215 | "\n",
1216 | "Но иногда пунктуация бывает и не шумом -- главное отталкиваться от задачи. Что будет если вообще не убирать пунктуацию?"
1217 | ]
1218 | },
1219 | {
1220 | "cell_type": "code",
1221 | "execution_count": 16,
1222 | "metadata": {},
1223 | "outputs": [
1224 | {
1225 | "name": "stdout",
1226 | "output_type": "stream",
1227 | "text": [
1228 | " precision recall f1-score support\n",
1229 | "\n",
1230 | " negative 1.00 1.00 1.00 27764\n",
1231 | " positive 1.00 1.00 1.00 28945\n",
1232 | "\n",
1233 | "avg / total 1.00 1.00 1.00 56709\n",
1234 | "\n"
1235 | ]
1236 | }
1237 | ],
1238 | "source": [
1239 | "vec = TfidfVectorizer(ngram_range=(1, 1), tokenizer=word_tokenize)\n",
1240 | "bow = vec.fit_transform(x_train)\n",
1241 | "clf = LogisticRegression(random_state=42)\n",
1242 | "clf.fit(bow, y_train)\n",
1243 | "pred = clf.predict(vec.transform(x_test))\n",
1244 | "print(classification_report(pred, y_test))"
1245 | ]
1246 | },
1247 | {
1248 | "cell_type": "markdown",
1249 | "metadata": {},
1250 | "source": [
1251 | "Шок! Стоило оставить пунктуацию -- и все метрики равны 1. Как это получилось? Среди неё были очень значимые токены (как вы думаете, какие?). Найдите фичи с самыми большими коэффициэнтами:"
1252 | ]
1253 | },
1254 | {
1255 | "cell_type": "code",
1256 | "execution_count": null,
1257 | "metadata": {},
1258 | "outputs": [],
1259 | "source": []
1260 | },
1261 | {
1262 | "cell_type": "markdown",
1263 | "metadata": {},
1264 | "source": [
1265 | "Посмотрим, как один из супер-значительных токенов справится с классификацией безо всякого машинного обучения:"
1266 | ]
1267 | },
1268 | {
1269 | "cell_type": "code",
1270 | "execution_count": 37,
1271 | "metadata": {},
1272 | "outputs": [
1273 | {
1274 | "name": "stdout",
1275 | "output_type": "stream",
1276 | "text": [
1277 | " precision recall f1-score support\n",
1278 | "\n",
1279 | " negative 1.00 0.85 0.92 32733\n",
1280 | " positive 0.83 1.00 0.91 23976\n",
1281 | "\n",
1282 | "avg / total 0.93 0.91 0.91 56709\n",
1283 | "\n"
1284 | ]
1285 | }
1286 | ],
1287 | "source": [
1288 | "cool_token = \n",
1289 | "pred = ['positive' if cool_token in tweet else 'negative' for tweet in x_test]\n",
1290 | "print(classification_report(pred, y_test))"
1291 | ]
1292 | },
1293 | {
1294 | "cell_type": "markdown",
1295 | "metadata": {},
1296 | "source": [
1297 | "## Символьные n-граммы\n",
1298 | "\n",
1299 | "Теперь в качестве фичей используем, например, униграммы символов:"
1300 | ]
1301 | },
1302 | {
1303 | "cell_type": "code",
1304 | "execution_count": 39,
1305 | "metadata": {},
1306 | "outputs": [
1307 | {
1308 | "name": "stdout",
1309 | "output_type": "stream",
1310 | "text": [
1311 | " precision recall f1-score support\n",
1312 | "\n",
1313 | " negative 0.99 1.00 1.00 27667\n",
1314 | " positive 1.00 0.99 1.00 29042\n",
1315 | "\n",
1316 | "avg / total 1.00 1.00 1.00 56709\n",
1317 | "\n"
1318 | ]
1319 | }
1320 | ],
1321 | "source": [
1322 | "vec = CountVectorizer(analyzer='char', ngram_range=(1, 1))\n",
1323 | "bow = vec.fit_transform(x_train)\n",
1324 | "clf = LogisticRegression(random_state=42)\n",
1325 | "clf.fit(bow, y_train)\n",
1326 | "pred = clf.predict(vec.transform(x_test))\n",
1327 | "print(classification_report(pred, y_test))"
1328 | ]
1329 | },
1330 | {
1331 | "cell_type": "markdown",
1332 | "metadata": {},
1333 | "source": [
1334 | "В общем-то, теперь уже понятно, почему на этих данных здесь 1. Так или инчае, на символах классифицировать тоже можно: для некторых задач (например, для определения языка) фичи-символьные n-граммы решительно рулят.\n",
1335 | "\n",
1336 | "Ещё одна замечательная особенность фичей-символов: токенизация и лемматизация не нужна, можно использовать такой подход для языков, у которых нет готвых анализаторов."
1337 | ]
1338 | },
1339 | {
1340 | "cell_type": "markdown",
1341 | "metadata": {},
1342 | "source": [
1343 | "## Регулярки\n",
1344 | "\n",
1345 | "(если осталось время)\n",
1346 | "\n",
1347 | "Вообще, часто бывает так, что для конкретного случая нужен особый способ токенизации, и надо самостоятельно написать регулярку. Или, например, перед работой с текстом, надо почистить его от своеобразного мусора: упоминаний пользователей, url и так далее.\n",
1348 | "\n",
1349 | "Навык полезный, давайте в нём тоже потренируемся."
1350 | ]
1351 | },
1352 | {
1353 | "cell_type": "code",
1354 | "execution_count": 2,
1355 | "metadata": {},
1356 | "outputs": [],
1357 | "source": [
1358 | "import re"
1359 | ]
1360 | },
1361 | {
1362 | "cell_type": "markdown",
1363 | "metadata": {},
1364 | "source": [
1365 | "### findall\n",
1366 | "возвращает список всех найденных совпадений"
1367 | ]
1368 | },
1369 | {
1370 | "cell_type": "code",
1371 | "execution_count": 6,
1372 | "metadata": {},
1373 | "outputs": [
1374 | {
1375 | "name": "stdout",
1376 | "output_type": "stream",
1377 | "text": [
1378 | "['abcd', 'abca']\n"
1379 | ]
1380 | }
1381 | ],
1382 | "source": [
1383 | "result = re.findall('ab+c.', 'abcdefghijkabcabcxabc') \n",
1384 | "print(result)"
1385 | ]
1386 | },
1387 | {
1388 | "cell_type": "markdown",
1389 | "metadata": {},
1390 | "source": [
1391 | "Вопрос на внимательность: почему нет abcx?"
1392 | ]
1393 | },
1394 | {
1395 | "cell_type": "markdown",
1396 | "metadata": {},
1397 | "source": [
1398 | "**Задание**: вернуть список первых двух букв каждого слова в строке, состоящей из нескольких слов."
1399 | ]
1400 | },
1401 | {
1402 | "cell_type": "code",
1403 | "execution_count": null,
1404 | "metadata": {
1405 | "collapsed": true
1406 | },
1407 | "outputs": [],
1408 | "source": []
1409 | },
1410 | {
1411 | "cell_type": "markdown",
1412 | "metadata": {},
1413 | "source": [
1414 | "### split\n",
1415 | "разделяет строку по заданному шаблону\n"
1416 | ]
1417 | },
1418 | {
1419 | "cell_type": "code",
1420 | "execution_count": 7,
1421 | "metadata": {},
1422 | "outputs": [
1423 | {
1424 | "name": "stdout",
1425 | "output_type": "stream",
1426 | "text": [
1427 | "['itsy', ' bitsy', ' teenie', ' weenie']\n"
1428 | ]
1429 | }
1430 | ],
1431 | "source": [
1432 | "result = re.split(',', 'itsy, bitsy, teenie, weenie') \n",
1433 | "print(result)"
1434 | ]
1435 | },
1436 | {
1437 | "cell_type": "markdown",
1438 | "metadata": {},
1439 | "source": [
1440 | "можно указать максимальное количество разбиений"
1441 | ]
1442 | },
1443 | {
1444 | "cell_type": "code",
1445 | "execution_count": 8,
1446 | "metadata": {},
1447 | "outputs": [
1448 | {
1449 | "name": "stdout",
1450 | "output_type": "stream",
1451 | "text": [
1452 | "['itsy', ' bitsy', ' teenie, weenie']\n"
1453 | ]
1454 | }
1455 | ],
1456 | "source": [
1457 | "result = re.split(',', 'itsy, bitsy, teenie, weenie', maxsplit = 2) \n",
1458 | "print(result)"
1459 | ]
1460 | },
1461 | {
1462 | "cell_type": "markdown",
1463 | "metadata": {},
1464 | "source": [
1465 | "**Задание**: разбейте строку, состоящую из нескольких предложений, по точкам, но не более чем на 3 предложения."
1466 | ]
1467 | },
1468 | {
1469 | "cell_type": "code",
1470 | "execution_count": null,
1471 | "metadata": {
1472 | "collapsed": true
1473 | },
1474 | "outputs": [],
1475 | "source": []
1476 | },
1477 | {
1478 | "cell_type": "markdown",
1479 | "metadata": {},
1480 | "source": [
1481 | "### sub\n",
1482 | "ищет шаблон в строке и заменяет все совпадения на указанную подстроку\n",
1483 | "\n",
1484 | "параметры: (pattern, repl, string)"
1485 | ]
1486 | },
1487 | {
1488 | "cell_type": "code",
1489 | "execution_count": 9,
1490 | "metadata": {},
1491 | "outputs": [
1492 | {
1493 | "name": "stdout",
1494 | "output_type": "stream",
1495 | "text": [
1496 | "bbcbbc\n"
1497 | ]
1498 | }
1499 | ],
1500 | "source": [
1501 | "result = re.sub('a', 'b', 'abcabc')\n",
1502 | "print (result)"
1503 | ]
1504 | },
1505 | {
1506 | "cell_type": "markdown",
1507 | "metadata": {},
1508 | "source": [
1509 | "**Задание**: напишите регулярку, которая заменяет все цифры в строке на \"DIG\"."
1510 | ]
1511 | },
1512 | {
1513 | "cell_type": "code",
1514 | "execution_count": null,
1515 | "metadata": {
1516 | "collapsed": true
1517 | },
1518 | "outputs": [],
1519 | "source": []
1520 | },
1521 | {
1522 | "cell_type": "markdown",
1523 | "metadata": {},
1524 | "source": [
1525 | "**Задание**: напишите регулярку, которая убирает url из строки."
1526 | ]
1527 | },
1528 | {
1529 | "cell_type": "code",
1530 | "execution_count": null,
1531 | "metadata": {},
1532 | "outputs": [],
1533 | "source": []
1534 | },
1535 | {
1536 | "cell_type": "markdown",
1537 | "metadata": {},
1538 | "source": [
1539 | "### compile\n",
1540 | "компилирует регулярное выражение в отдельный объект"
1541 | ]
1542 | },
1543 | {
1544 | "cell_type": "code",
1545 | "execution_count": 10,
1546 | "metadata": {},
1547 | "outputs": [
1548 | {
1549 | "data": {
1550 | "text/plain": [
1551 | "['Слова', 'Да', 'больше', 'ещё', 'больше', 'слов', 'Что-то', 'ещё']"
1552 | ]
1553 | },
1554 | "execution_count": 10,
1555 | "metadata": {},
1556 | "output_type": "execute_result"
1557 | }
1558 | ],
1559 | "source": [
1560 | "# Пример: построение списка всех слов строки:\n",
1561 | "prog = re.compile('[А-Яа-яё\\-]+')\n",
1562 | "prog.findall(\"Слова? Да, больше, ещё больше слов! Что-то ещё.\")"
1563 | ]
1564 | },
1565 | {
1566 | "cell_type": "markdown",
1567 | "metadata": {},
1568 | "source": [
1569 | "**Задание**: для выбранной строки постройте список слов, которые длиннее трех символов."
1570 | ]
1571 | },
1572 | {
1573 | "cell_type": "code",
1574 | "execution_count": null,
1575 | "metadata": {
1576 | "collapsed": true
1577 | },
1578 | "outputs": [],
1579 | "source": []
1580 | },
1581 | {
1582 | "cell_type": "markdown",
1583 | "metadata": {},
1584 | "source": [
1585 | "**Задание**: вернуть список доменов (@gmail.com) из списка адресов электронной почты:\n",
1586 | "\n",
1587 | "```\n",
1588 | "abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz\n",
1589 | "```"
1590 | ]
1591 | },
1592 | {
1593 | "cell_type": "code",
1594 | "execution_count": null,
1595 | "metadata": {
1596 | "collapsed": true
1597 | },
1598 | "outputs": [],
1599 | "source": []
1600 | },
1601 | {
1602 | "cell_type": "markdown",
1603 | "metadata": {},
1604 | "source": [
1605 | "Если всё ещё осталось время: [регулярочный кроссворд ¯\\_(ツ)_/¯](https://mariolurig.com/crossword/)"
1606 | ]
1607 | }
1608 | ],
1609 | "metadata": {
1610 | "kernelspec": {
1611 | "display_name": "Python 3",
1612 | "language": "python",
1613 | "name": "python3"
1614 | },
1615 | "language_info": {
1616 | "codemirror_mode": {
1617 | "name": "ipython",
1618 | "version": 3
1619 | },
1620 | "file_extension": ".py",
1621 | "mimetype": "text/x-python",
1622 | "name": "python",
1623 | "nbconvert_exporter": "python",
1624 | "pygments_lexer": "ipython3",
1625 | "version": "3.5.2"
1626 | }
1627 | },
1628 | "nbformat": 4,
1629 | "nbformat_minor": 2
1630 | }
1631 |
--------------------------------------------------------------------------------
/seminars/1/1_regex.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "https://tproger.ru/translations/regular-expression-python/"
8 | ]
9 | },
10 | {
11 | "cell_type": "code",
12 | "execution_count": 1,
13 | "metadata": {
14 | "collapsed": true
15 | },
16 | "outputs": [],
17 | "source": [
18 | "import re"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "# match\n",
26 | "ищет по заданному шаблону в начале строки"
27 | ]
28 | },
29 | {
30 | "cell_type": "code",
31 | "execution_count": 2,
32 | "metadata": {},
33 | "outputs": [
34 | {
35 | "name": "stdout",
36 | "output_type": "stream",
37 | "text": [
38 | "<_sre.SRE_Match object; span=(0, 4), match='abcd'>\n"
39 | ]
40 | }
41 | ],
42 | "source": [
43 | "result = re.match('ab+c.', 'abcdefghijkabcabc') # ищем по шаблону 'ab+c.' \n",
44 | "print (result) # совпадение найдено:"
45 | ]
46 | },
47 | {
48 | "cell_type": "code",
49 | "execution_count": 3,
50 | "metadata": {},
51 | "outputs": [
52 | {
53 | "name": "stdout",
54 | "output_type": "stream",
55 | "text": [
56 | "abcd\n"
57 | ]
58 | }
59 | ],
60 | "source": [
61 | "print(result.group(0)) # выводим найденное совпадение"
62 | ]
63 | },
64 | {
65 | "cell_type": "code",
66 | "execution_count": 4,
67 | "metadata": {},
68 | "outputs": [
69 | {
70 | "name": "stdout",
71 | "output_type": "stream",
72 | "text": [
73 | "None\n"
74 | ]
75 | }
76 | ],
77 | "source": [
78 | "result = re.match('abc.', 'abdefghijkabcabc')\n",
79 | "print(result) # совпадение не найдено"
80 | ]
81 | },
82 | {
83 | "cell_type": "markdown",
84 | "metadata": {},
85 | "source": [
86 | "## Задание 1:\n",
87 | "Проверьте, начинаются ли строки c заглавной буквы и если да, то вывести эту заглавную букву. Придумайте свои примеры строк для проверки."
88 | ]
89 | },
90 | {
91 | "cell_type": "code",
92 | "execution_count": null,
93 | "metadata": {
94 | "collapsed": true
95 | },
96 | "outputs": [],
97 | "source": []
98 | },
99 | {
100 | "cell_type": "markdown",
101 | "metadata": {},
102 | "source": [
103 | "# search\n",
104 | "ищет по всей строке, возвращает только первое найденное совпадение"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": 5,
110 | "metadata": {},
111 | "outputs": [
112 | {
113 | "name": "stdout",
114 | "output_type": "stream",
115 | "text": [
116 | "<_sre.SRE_Match object; span=(4, 8), match='abch'>\n"
117 | ]
118 | }
119 | ],
120 | "source": [
121 | "result = re.search('ab+c.', 'aefgabchijkabcabc') \n",
122 | "print(result) "
123 | ]
124 | },
125 | {
126 | "cell_type": "markdown",
127 | "metadata": {},
128 | "source": [
129 | "## Задание 2\n",
130 | "Проверьте, есть ли в строке вопросительный знак. Придумайте свои примеры для проверки."
131 | ]
132 | },
133 | {
134 | "cell_type": "code",
135 | "execution_count": null,
136 | "metadata": {
137 | "collapsed": true
138 | },
139 | "outputs": [],
140 | "source": []
141 | },
142 | {
143 | "cell_type": "markdown",
144 | "metadata": {},
145 | "source": [
146 | "# findall\n",
147 | "возвращает список всех найденных совпадений"
148 | ]
149 | },
150 | {
151 | "cell_type": "code",
152 | "execution_count": 6,
153 | "metadata": {},
154 | "outputs": [
155 | {
156 | "name": "stdout",
157 | "output_type": "stream",
158 | "text": [
159 | "['abcd', 'abca']\n"
160 | ]
161 | }
162 | ],
163 | "source": [
164 | "result = re.findall('ab+c.', 'abcdefghijkabcabcxabc') \n",
165 | "print(result)"
166 | ]
167 | },
168 | {
169 | "cell_type": "markdown",
170 | "metadata": {},
171 | "source": [
172 | "Вопросы: \n",
173 | "1) почему нет последнего abc?\n",
174 | "2) почему нет abcx?"
175 | ]
176 | },
177 | {
178 | "cell_type": "markdown",
179 | "metadata": {},
180 | "source": [
181 | "## Задание 3\n",
182 | "Вернуть список первых двух букв каждого слова в строке, состоящей из нескольких слов."
183 | ]
184 | },
185 | {
186 | "cell_type": "code",
187 | "execution_count": null,
188 | "metadata": {
189 | "collapsed": true
190 | },
191 | "outputs": [],
192 | "source": []
193 | },
194 | {
195 | "cell_type": "markdown",
196 | "metadata": {},
197 | "source": [
198 | "# split\n",
199 | "разделяет строку по заданному шаблону\n"
200 | ]
201 | },
202 | {
203 | "cell_type": "code",
204 | "execution_count": 7,
205 | "metadata": {},
206 | "outputs": [
207 | {
208 | "name": "stdout",
209 | "output_type": "stream",
210 | "text": [
211 | "['itsy', ' bitsy', ' teenie', ' weenie']\n"
212 | ]
213 | }
214 | ],
215 | "source": [
216 | "result = re.split(',', 'itsy, bitsy, teenie, weenie') \n",
217 | "print(result)"
218 | ]
219 | },
220 | {
221 | "cell_type": "markdown",
222 | "metadata": {},
223 | "source": [
224 | "можно указать максимальное количество разбиений"
225 | ]
226 | },
227 | {
228 | "cell_type": "code",
229 | "execution_count": 8,
230 | "metadata": {},
231 | "outputs": [
232 | {
233 | "name": "stdout",
234 | "output_type": "stream",
235 | "text": [
236 | "['itsy', ' bitsy', ' teenie, weenie']\n"
237 | ]
238 | }
239 | ],
240 | "source": [
241 | "result = re.split(',', 'itsy, bitsy, teenie, weenie', maxsplit = 2) \n",
242 | "print(result)"
243 | ]
244 | },
245 | {
246 | "cell_type": "markdown",
247 | "metadata": {},
248 | "source": [
249 | "## Задание 4\n",
250 | "Разбейте строку, состоящую из нескольких предложений, по точкам, но не более чем на 3 предложения."
251 | ]
252 | },
253 | {
254 | "cell_type": "code",
255 | "execution_count": null,
256 | "metadata": {
257 | "collapsed": true
258 | },
259 | "outputs": [],
260 | "source": []
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "# sub\n",
267 | "ищет шаблон в строке и заменяет все совпадения на указанную подстроку\n",
268 | "\n",
269 | "параметры: (pattern, repl, string)"
270 | ]
271 | },
272 | {
273 | "cell_type": "code",
274 | "execution_count": 9,
275 | "metadata": {},
276 | "outputs": [
277 | {
278 | "name": "stdout",
279 | "output_type": "stream",
280 | "text": [
281 | "bbcbbc\n"
282 | ]
283 | }
284 | ],
285 | "source": [
286 | "result = re.sub('a', 'b', 'abcabc')\n",
287 | "print (result)"
288 | ]
289 | },
290 | {
291 | "cell_type": "markdown",
292 | "metadata": {},
293 | "source": [
294 | "## Задание 5:\n",
295 | "Замените все цифры на звездочки."
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": null,
301 | "metadata": {
302 | "collapsed": true
303 | },
304 | "outputs": [],
305 | "source": []
306 | },
307 | {
308 | "cell_type": "markdown",
309 | "metadata": {},
310 | "source": [
311 | "# compile\n",
312 | "компилирует регулярное выражение в отдельный объект"
313 | ]
314 | },
315 | {
316 | "cell_type": "code",
317 | "execution_count": 10,
318 | "metadata": {},
319 | "outputs": [
320 | {
321 | "data": {
322 | "text/plain": [
323 | "['Слова', 'Да', 'больше', 'ещё', 'больше', 'слов', 'Что-то', 'ещё']"
324 | ]
325 | },
326 | "execution_count": 10,
327 | "metadata": {},
328 | "output_type": "execute_result"
329 | }
330 | ],
331 | "source": [
332 | "# Пример: построение списка всех слов строки:\n",
333 | "prog = re.compile('[А-Яа-яё\\-]+')\n",
334 | "prog.findall(\"Слова? Да, больше, ещё больше слов! Что-то ещё.\")"
335 | ]
336 | },
337 | {
338 | "cell_type": "markdown",
339 | "metadata": {},
340 | "source": [
341 | "## Задание 6\n",
342 | "Для выбранной строки постройте список слов, которые длиннее трех символов."
343 | ]
344 | },
345 | {
346 | "cell_type": "code",
347 | "execution_count": null,
348 | "metadata": {
349 | "collapsed": true
350 | },
351 | "outputs": [],
352 | "source": []
353 | },
354 | {
355 | "cell_type": "markdown",
356 | "metadata": {},
357 | "source": [
358 | "## Задание 7\n",
359 | "Вернуть первое слово строки"
360 | ]
361 | },
362 | {
363 | "cell_type": "code",
364 | "execution_count": null,
365 | "metadata": {
366 | "collapsed": true
367 | },
368 | "outputs": [],
369 | "source": []
370 | },
371 | {
372 | "cell_type": "markdown",
373 | "metadata": {},
374 | "source": [
375 | "## Задание 8\n",
376 | "Вернуть список доменов (@gmail.com) из списка адресов электронной почты:\n",
377 | "\n",
378 | "abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz"
379 | ]
380 | },
381 | {
382 | "cell_type": "code",
383 | "execution_count": null,
384 | "metadata": {
385 | "collapsed": true
386 | },
387 | "outputs": [],
388 | "source": []
389 | }
390 | ],
391 | "metadata": {
392 | "kernelspec": {
393 | "display_name": "Python 3",
394 | "language": "python",
395 | "name": "python3"
396 | },
397 | "language_info": {
398 | "codemirror_mode": {
399 | "name": "ipython",
400 | "version": 3
401 | },
402 | "file_extension": ".py",
403 | "mimetype": "text/x-python",
404 | "name": "python",
405 | "nbconvert_exporter": "python",
406 | "pygments_lexer": "ipython3",
407 | "version": "3.7.2"
408 | }
409 | },
410 | "nbformat": 4,
411 | "nbformat_minor": 2
412 | }
413 |
--------------------------------------------------------------------------------
/seminars/1/1_regex.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/1/1_regex.pdf
--------------------------------------------------------------------------------
/seminars/12/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/12/.DS_Store
--------------------------------------------------------------------------------
/seminars/12/active_learning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/12/active_learning.png
--------------------------------------------------------------------------------
/seminars/12/sem12-active-learning.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "## Active Learning"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "Активное обучение $-$ класс алгоритмов обучения моделей машинного обучения. Алгоритмы активного обучения отличаются тем, могут интерактивно запрашивать пользователя (или некоторый другой источник информации) для разметки новых примеров данных."
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "
"
22 | ]
23 | },
24 | {
25 | "cell_type": "markdown",
26 | "metadata": {},
27 | "source": [
28 | "## Active Learning Strategies"
29 | ]
30 | },
31 | {
32 | "cell_type": "markdown",
33 | "metadata": {},
34 | "source": [
35 | "#### Pool-Based Sampling"
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "В этом сценарии экземпляры извлекаются из всего пула данных и им присваивается информативная оценка, которая показывает, насколько хорошо текущий алгоритм «понимает» данные. \n",
43 | "\n",
44 | "Затем система выбираются и размечаются наиболее информативные примеры."
45 | ]
46 | },
47 | {
48 | "cell_type": "markdown",
49 | "metadata": {},
50 | "source": [
51 | "#### Uncertainty sampling"
52 | ]
53 | },
54 | {
55 | "cell_type": "markdown",
56 | "metadata": {},
57 | "source": [
58 | "\n",
59 | "В рамках этого алгоритма размечаются те примеры, на которых текущая модель наименее уверена.\n",
60 | "\n",
61 | "В качестве функций \"уверенности\" можно использовать вероятности классов или расстояния до разделяющей гиперплоскости."
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "#### Membership Query Synthesis"
69 | ]
70 | },
71 | {
72 | "cell_type": "markdown",
73 | "metadata": {},
74 | "source": [
75 | "Здесь алгритм обучения модели генерирует свои собственные примеры из некоторого настраиваемого распределения. \n",
76 | "Эти сгенерированные примеры отправляются на разметку и модель дообучается с учетом разметки этих примеров."
77 | ]
78 | },
79 | {
80 | "cell_type": "markdown",
81 | "metadata": {},
82 | "source": [
83 | "#### Query by Committee"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Идея: построить ансамбль моделей $a_1,...,a_T$. \n",
91 | "\n",
92 | "Выбирать новые объекты $x_i$ с наибольшей несогласованностью решений ансамбля моделей.\n",
93 | "\n"
94 | ]
95 | },
96 | {
97 | "cell_type": "markdown",
98 | "metadata": {},
99 | "source": [
100 | "Принцип максимума энтропии: выбираем $x_i$, на котором $a_t(x_i)$ максимально различны."
101 | ]
102 | },
103 | {
104 | "cell_type": "markdown",
105 | "metadata": {},
106 | "source": [
107 | "Принцип максимума средней $KL$-дивергенции:выбираем $x_i$ , на котором $P_t(y|x_i)$ максимально различны:\n",
108 | "\n",
109 | "$С(y|u) = \\frac{1}{T}\\sum_{t=1}^T P_t(y|u)$ - консенсус комитета "
110 | ]
111 | },
112 | {
113 | "cell_type": "markdown",
114 | "metadata": {},
115 | "source": [
116 | "## SVM для Active Learning"
117 | ]
118 | },
119 | {
120 | "cell_type": "markdown",
121 | "metadata": {},
122 | "source": [
123 | "Некоторые активные алгоритмы обучения построены на алгоритме SVM и используют структуру SVM для определения того, какие точки данных нужно размечать. \n",
124 | "\n",
125 | "SVM используется для определения уверенности модели в предсказании на каждом из примеров выборки. \n",
126 | "В качестве меры уверенности служит расстояние от объекта до построенной не текущей итерации разделяющей гиперплоскости."
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "## Active Learning for texts classification"
134 | ]
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {},
139 | "source": [
140 | "Рассмотрим алгоритм pool-based active learning на примере задачи классификации твитов по тональности."
141 | ]
142 | },
143 | {
144 | "cell_type": "markdown",
145 | "metadata": {},
146 | "source": [
147 | "\n",
148 | "1. Разделить данные на X_pool (выборка, которую можно размечать) и X_test.\n",
149 | "2. Выбрать $k$ примеров из X_pool для начального X_train и разметить их. Остальные данные в X_pool $-$ валидационное множество. \n",
150 | "3. Обучить модель на X_train.\n",
151 | "5. Сделать predict обученной моделью на X_pool, вычислить вероятности для каждого $x_i$.\n",
152 | "6. Вычислить качество работы модели на X_test.\n",
153 | "7. Выбрать $k$ наиболее информативных объектов из X_pool, основываясь на уверенности модели в каждом из объектов (например, вероятности классов).\n",
154 | "8. Переменести эти $k$ выбранных объектов в X_train.\n",
155 | "9. Если качество работы модели на X_test достаточное, то останавливаемся, иначе возвращаемся к шагу 3."
156 | ]
157 | },
158 | {
159 | "cell_type": "code",
160 | "execution_count": 60,
161 | "metadata": {},
162 | "outputs": [],
163 | "source": [
164 | "from sklearn.metrics import f1_score"
165 | ]
166 | },
167 | {
168 | "cell_type": "code",
169 | "execution_count": 61,
170 | "metadata": {},
171 | "outputs": [],
172 | "source": [
173 | "import pandas as pd\n",
174 | "import numpy as np\n",
175 | "from sklearn.metrics import *\n",
176 | "from sklearn.model_selection import train_test_split\n",
177 | "from sklearn.pipeline import Pipeline\n",
178 | "from nltk import ngrams\n",
179 | "\n",
180 | "from sklearn.linear_model import LogisticRegression \n",
181 | "from sklearn.feature_extraction.text import CountVectorizer"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": 62,
187 | "metadata": {},
188 | "outputs": [],
189 | "source": [
190 | "# positive = pd.read_csv('positive.csv', sep=';', usecols=[3], names=['text'])\n",
191 | "# positive['label'] = ['positive'] * len(positive)\n",
192 | "# negative = pd.read_csv('negative.csv', sep=';', usecols=[3], names=['text'])\n",
193 | "# negative['label'] = ['negative'] * len(negative)\n",
194 | "# df = positive.append(negative)"
195 | ]
196 | },
197 | {
198 | "cell_type": "code",
199 | "execution_count": 63,
200 | "metadata": {},
201 | "outputs": [
202 | {
203 | "name": "stdout",
204 | "output_type": "stream",
205 | "text": [
206 | "(5572, 2)\n"
207 | ]
208 | },
209 | {
210 | "data": {
211 | "text/html": [
212 | "\n",
213 | "\n",
226 | "
\n",
227 | " \n",
228 | " \n",
229 | " | \n",
230 | " Category | \n",
231 | " Message | \n",
232 | "
\n",
233 | " \n",
234 | " \n",
235 | " \n",
236 | " 0 | \n",
237 | " ham | \n",
238 | " Go until jurong point, crazy.. Available only ... | \n",
239 | "
\n",
240 | " \n",
241 | " 1 | \n",
242 | " ham | \n",
243 | " Ok lar... Joking wif u oni... | \n",
244 | "
\n",
245 | " \n",
246 | " 2 | \n",
247 | " spam | \n",
248 | " Free entry in 2 a wkly comp to win FA Cup fina... | \n",
249 | "
\n",
250 | " \n",
251 | " 3 | \n",
252 | " ham | \n",
253 | " U dun say so early hor... U c already then say... | \n",
254 | "
\n",
255 | " \n",
256 | " 4 | \n",
257 | " ham | \n",
258 | " Nah I don't think he goes to usf, he lives aro... | \n",
259 | "
\n",
260 | " \n",
261 | "
\n",
262 | "
"
263 | ],
264 | "text/plain": [
265 | " Category Message\n",
266 | "0 ham Go until jurong point, crazy.. Available only ...\n",
267 | "1 ham Ok lar... Joking wif u oni...\n",
268 | "2 spam Free entry in 2 a wkly comp to win FA Cup fina...\n",
269 | "3 ham U dun say so early hor... U c already then say...\n",
270 | "4 ham Nah I don't think he goes to usf, he lives aro..."
271 | ]
272 | },
273 | "execution_count": 63,
274 | "metadata": {},
275 | "output_type": "execute_result"
276 | }
277 | ],
278 | "source": [
279 | "df = pd.read_csv('spam_text_classification_data.csv')\n",
280 | "print(df.shape)\n",
281 | "df.head()"
282 | ]
283 | },
284 | {
285 | "cell_type": "code",
286 | "execution_count": 64,
287 | "metadata": {},
288 | "outputs": [],
289 | "source": [
290 | "df['label'] = [0 if category == 'ham' else 1 for category in df['Category']]"
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 | "execution_count": 65,
296 | "metadata": {},
297 | "outputs": [],
298 | "source": [
299 | "def get_confidence(class_probs):\n",
300 | " return abs(0.5-class_probs[0])"
301 | ]
302 | },
303 | {
304 | "cell_type": "code",
305 | "execution_count": 66,
306 | "metadata": {},
307 | "outputs": [
308 | {
309 | "name": "stdout",
310 | "output_type": "stream",
311 | "text": [
312 | "50 train samples\n",
313 | " precision recall f1-score support\n",
314 | "\n",
315 | " 0 1.00 0.91 0.95 1072\n",
316 | " 1 0.30 0.98 0.45 43\n",
317 | "\n",
318 | " micro avg 0.91 0.91 0.91 1115\n",
319 | " macro avg 0.65 0.94 0.70 1115\n",
320 | "weighted avg 0.97 0.91 0.93 1115\n",
321 | "\n",
322 | "60 train samples\n",
323 | " precision recall f1-score support\n",
324 | "\n",
325 | " 0 0.99 0.93 0.96 1037\n",
326 | " 1 0.49 0.90 0.64 78\n",
327 | "\n",
328 | " micro avg 0.93 0.93 0.93 1115\n",
329 | " macro avg 0.74 0.91 0.80 1115\n",
330 | "weighted avg 0.96 0.93 0.94 1115\n",
331 | "\n",
332 | "70 train samples\n",
333 | " precision recall f1-score support\n",
334 | "\n",
335 | " 0 0.99 0.95 0.97 1012\n",
336 | " 1 0.65 0.90 0.76 103\n",
337 | "\n",
338 | " micro avg 0.95 0.95 0.95 1115\n",
339 | " macro avg 0.82 0.93 0.86 1115\n",
340 | "weighted avg 0.96 0.95 0.95 1115\n",
341 | "\n",
342 | "80 train samples\n",
343 | " precision recall f1-score support\n",
344 | "\n",
345 | " 0 0.99 0.96 0.97 1006\n",
346 | " 1 0.69 0.90 0.78 109\n",
347 | "\n",
348 | " micro avg 0.95 0.95 0.95 1115\n",
349 | " macro avg 0.84 0.93 0.88 1115\n",
350 | "weighted avg 0.96 0.95 0.95 1115\n",
351 | "\n",
352 | "90 train samples\n",
353 | " precision recall f1-score support\n",
354 | "\n",
355 | " 0 0.99 0.96 0.98 1007\n",
356 | " 1 0.72 0.94 0.82 108\n",
357 | "\n",
358 | " micro avg 0.96 0.96 0.96 1115\n",
359 | " macro avg 0.86 0.95 0.90 1115\n",
360 | "weighted avg 0.97 0.96 0.96 1115\n",
361 | "\n",
362 | "100 train samples\n",
363 | " precision recall f1-score support\n",
364 | "\n",
365 | " 0 0.99 0.97 0.98 994\n",
366 | " 1 0.80 0.93 0.86 121\n",
367 | "\n",
368 | " micro avg 0.97 0.97 0.97 1115\n",
369 | " macro avg 0.89 0.95 0.92 1115\n",
370 | "weighted avg 0.97 0.97 0.97 1115\n",
371 | "\n",
372 | "110 train samples\n",
373 | " precision recall f1-score support\n",
374 | "\n",
375 | " 0 0.99 0.98 0.98 985\n",
376 | " 1 0.84 0.92 0.88 130\n",
377 | "\n",
378 | " micro avg 0.97 0.97 0.97 1115\n",
379 | " macro avg 0.91 0.95 0.93 1115\n",
380 | "weighted avg 0.97 0.97 0.97 1115\n",
381 | "\n",
382 | "120 train samples\n",
383 | " precision recall f1-score support\n",
384 | "\n",
385 | " 0 0.99 0.98 0.99 988\n",
386 | " 1 0.85 0.95 0.90 127\n",
387 | "\n",
388 | " micro avg 0.98 0.98 0.98 1115\n",
389 | " macro avg 0.92 0.97 0.94 1115\n",
390 | "weighted avg 0.98 0.98 0.98 1115\n",
391 | "\n",
392 | "130 train samples\n",
393 | " precision recall f1-score support\n",
394 | "\n",
395 | " 0 0.99 0.98 0.99 979\n",
396 | " 1 0.89 0.93 0.91 136\n",
397 | "\n",
398 | " micro avg 0.98 0.98 0.98 1115\n",
399 | " macro avg 0.94 0.96 0.95 1115\n",
400 | "weighted avg 0.98 0.98 0.98 1115\n",
401 | "\n",
402 | "140 train samples\n",
403 | " precision recall f1-score support\n",
404 | "\n",
405 | " 0 0.99 0.98 0.99 981\n",
406 | " 1 0.87 0.93 0.90 134\n",
407 | "\n",
408 | " micro avg 0.97 0.97 0.97 1115\n",
409 | " macro avg 0.93 0.95 0.94 1115\n",
410 | "weighted avg 0.98 0.97 0.98 1115\n",
411 | "\n",
412 | "150 train samples\n",
413 | " precision recall f1-score support\n",
414 | "\n",
415 | " 0 0.99 0.98 0.99 984\n",
416 | " 1 0.87 0.95 0.91 131\n",
417 | "\n",
418 | " micro avg 0.98 0.98 0.98 1115\n",
419 | " macro avg 0.93 0.96 0.95 1115\n",
420 | "weighted avg 0.98 0.98 0.98 1115\n",
421 | "\n",
422 | "160 train samples\n",
423 | " precision recall f1-score support\n",
424 | "\n",
425 | " 0 0.99 0.98 0.99 989\n",
426 | " 1 0.85 0.95 0.90 126\n",
427 | "\n",
428 | " micro avg 0.97 0.97 0.97 1115\n",
429 | " macro avg 0.92 0.97 0.94 1115\n",
430 | "weighted avg 0.98 0.97 0.98 1115\n",
431 | "\n",
432 | "170 train samples\n",
433 | " precision recall f1-score support\n",
434 | "\n",
435 | " 0 0.99 0.98 0.99 988\n",
436 | " 1 0.86 0.96 0.91 127\n",
437 | "\n",
438 | " micro avg 0.98 0.98 0.98 1115\n",
439 | " macro avg 0.93 0.97 0.95 1115\n",
440 | "weighted avg 0.98 0.98 0.98 1115\n",
441 | "\n",
442 | "180 train samples\n",
443 | " precision recall f1-score support\n",
444 | "\n",
445 | " 0 0.99 0.98 0.99 983\n",
446 | " 1 0.88 0.95 0.91 132\n",
447 | "\n",
448 | " micro avg 0.98 0.98 0.98 1115\n",
449 | " macro avg 0.94 0.96 0.95 1115\n",
450 | "weighted avg 0.98 0.98 0.98 1115\n",
451 | "\n",
452 | "190 train samples\n",
453 | " precision recall f1-score support\n",
454 | "\n",
455 | " 0 0.99 0.98 0.99 984\n",
456 | " 1 0.89 0.96 0.92 131\n",
457 | "\n",
458 | " micro avg 0.98 0.98 0.98 1115\n",
459 | " macro avg 0.94 0.97 0.96 1115\n",
460 | "weighted avg 0.98 0.98 0.98 1115\n",
461 | "\n",
462 | "200 train samples\n",
463 | " precision recall f1-score support\n",
464 | "\n",
465 | " 0 1.00 0.98 0.99 988\n",
466 | " 1 0.87 0.98 0.92 127\n",
467 | "\n",
468 | " micro avg 0.98 0.98 0.98 1115\n",
469 | " macro avg 0.94 0.98 0.96 1115\n",
470 | "weighted avg 0.98 0.98 0.98 1115\n",
471 | "\n",
472 | "210 train samples\n",
473 | " precision recall f1-score support\n",
474 | "\n",
475 | " 0 1.00 0.99 0.99 984\n",
476 | " 1 0.90 0.98 0.94 131\n",
477 | "\n",
478 | " micro avg 0.98 0.98 0.98 1115\n",
479 | " macro avg 0.95 0.98 0.96 1115\n",
480 | "weighted avg 0.99 0.98 0.99 1115\n",
481 | "\n",
482 | "220 train samples\n",
483 | " precision recall f1-score support\n",
484 | "\n",
485 | " 0 1.00 0.98 0.99 986\n",
486 | " 1 0.89 0.98 0.93 129\n",
487 | "\n",
488 | " micro avg 0.98 0.98 0.98 1115\n",
489 | " macro avg 0.94 0.98 0.96 1115\n",
490 | "weighted avg 0.98 0.98 0.98 1115\n",
491 | "\n",
492 | "230 train samples\n",
493 | " precision recall f1-score support\n",
494 | "\n",
495 | " 0 1.00 0.98 0.99 986\n",
496 | " 1 0.89 0.98 0.94 129\n",
497 | "\n",
498 | " micro avg 0.98 0.98 0.98 1115\n",
499 | " macro avg 0.95 0.98 0.96 1115\n",
500 | "weighted avg 0.99 0.98 0.99 1115\n",
501 | "\n",
502 | "240 train samples\n",
503 | " precision recall f1-score support\n",
504 | "\n",
505 | " 0 1.00 0.99 0.99 983\n",
506 | " 1 0.92 0.98 0.95 132\n",
507 | "\n",
508 | " micro avg 0.99 0.99 0.99 1115\n",
509 | " macro avg 0.96 0.99 0.97 1115\n",
510 | "weighted avg 0.99 0.99 0.99 1115\n",
511 | "\n",
512 | "250 train samples\n",
513 | " precision recall f1-score support\n",
514 | "\n",
515 | " 0 1.00 0.99 0.99 982\n",
516 | " 1 0.92 0.98 0.95 133\n",
517 | "\n",
518 | " micro avg 0.99 0.99 0.99 1115\n",
519 | " macro avg 0.96 0.99 0.97 1115\n",
520 | "weighted avg 0.99 0.99 0.99 1115\n",
521 | "\n"
522 | ]
523 | }
524 | ],
525 | "source": [
526 | "train_size = 50\n",
527 | "\n",
528 | "dataset_size = X.shape[0]\n",
529 | "target_score = 0.95\n",
530 | "score = 0\n",
531 | "step = 10\n",
532 | "\n",
533 | "X_train = X[:train_size]\n",
534 | "y_train = y[:train_size]\n",
535 | "X_pool = X[train_size:]\n",
536 | "y_pool = y[train_size:]\n",
537 | "\n",
538 | "scores = [0]\n",
539 | "train_szs = [0]\n",
540 | "\n",
541 | "while score < target_score and train_size <= dataset_size:\n",
542 | " vec = CountVectorizer(ngram_range=(1, 1))\n",
543 | " bow = vec.fit_transform(X_train)\n",
544 | " clf = clf.fit(bow,y_train)\n",
545 | " pred = clf.predict(vec.transform(X_test))\n",
546 | " \n",
547 | " print(\"{0} train samples\".format(train_size))\n",
548 | " print(classification_report(pred, y_test))\n",
549 | " score = f1_score(pred, y_test)\n",
550 | " scores.append(score)\n",
551 | " train_szs.append(train_size)\n",
552 | " \n",
553 | " pred_probs = clf.predict_proba(vec.transform(X_pool))\n",
554 | " confidences = [get_confidence(probs) for probs in pred_probs]\n",
555 | " \n",
556 | " X_train = np.concatenate([X_train, X_pool[np.argsort(confidences)[:step]]])\n",
557 | " y_train = np.concatenate([y_train, y_pool[np.argsort(confidences)[:step]]])\n",
558 | " X_pool = X_pool[sorted(np.argsort(confidences)[step:])]\n",
559 | " y_pool = y_pool[sorted(np.argsort(confidences)[step:])]\n",
560 | " train_size += step"
561 | ]
562 | },
563 | {
564 | "cell_type": "code",
565 | "execution_count": 67,
566 | "metadata": {},
567 | "outputs": [
568 | {
569 | "name": "stdout",
570 | "output_type": "stream",
571 | "text": [
572 | "4457 train samples\n",
573 | " precision recall f1-score support\n",
574 | "\n",
575 | " 0 1.00 0.99 0.99 986\n",
576 | " 1 0.91 1.00 0.95 129\n",
577 | "\n",
578 | " micro avg 0.99 0.99 0.99 1115\n",
579 | " macro avg 0.95 0.99 0.97 1115\n",
580 | "weighted avg 0.99 0.99 0.99 1115\n",
581 | "\n"
582 | ]
583 | }
584 | ],
585 | "source": [
586 | "vec = CountVectorizer(ngram_range=(1, 1))\n",
587 | "bow = vec.fit_transform(X)\n",
588 | "clf = clf.fit(bow,y)\n",
589 | "pred = clf.predict(vec.transform(X_test))\n",
590 | "\n",
591 | "print(\"{0} train samples\".format(dataset_size))\n",
592 | "print(classification_report(pred, y_test))"
593 | ]
594 | },
595 | {
596 | "cell_type": "code",
597 | "execution_count": 68,
598 | "metadata": {},
599 | "outputs": [],
600 | "source": [
601 | "from matplotlib import pyplot as plt\n",
602 | "\n",
603 | "%matplotlib inline"
604 | ]
605 | },
606 | {
607 | "cell_type": "code",
608 | "execution_count": 69,
609 | "metadata": {},
610 | "outputs": [
611 | {
612 | "data": {
613 | "text/plain": [
614 | "[]"
615 | ]
616 | },
617 | "execution_count": 69,
618 | "metadata": {},
619 | "output_type": "execute_result"
620 | },
621 | {
622 | "data": {
623 | "image/png": "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\n",
624 | "text/plain": [
625 | ""
626 | ]
627 | },
628 | "metadata": {
629 | "needs_background": "light"
630 | },
631 | "output_type": "display_data"
632 | }
633 | ],
634 | "source": [
635 | "plt.plot(train_szs,scores)\n",
636 | "plt.plot(train_szs, [0.95 for sz in train_szs])"
637 | ]
638 | },
639 | {
640 | "cell_type": "markdown",
641 | "metadata": {},
642 | "source": [
643 | "Можно видеть, что для достижения лучшего качества на этом датасете дсотаточно обучиться на 300 правильно выбранных примерах."
644 | ]
645 | },
646 | {
647 | "cell_type": "code",
648 | "execution_count": null,
649 | "metadata": {},
650 | "outputs": [],
651 | "source": []
652 | }
653 | ],
654 | "metadata": {
655 | "kernelspec": {
656 | "display_name": "Python 3",
657 | "language": "python",
658 | "name": "python3"
659 | },
660 | "language_info": {
661 | "codemirror_mode": {
662 | "name": "ipython",
663 | "version": 3
664 | },
665 | "file_extension": ".py",
666 | "mimetype": "text/x-python",
667 | "name": "python",
668 | "nbconvert_exporter": "python",
669 | "pygments_lexer": "ipython3",
670 | "version": "3.7.4"
671 | }
672 | },
673 | "nbformat": 4,
674 | "nbformat_minor": 4
675 | }
676 |
--------------------------------------------------------------------------------
/seminars/4/images/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/.DS_Store
--------------------------------------------------------------------------------
/seminars/4/images/LSTM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/LSTM.png
--------------------------------------------------------------------------------
/seminars/4/images/LSTM_rnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/LSTM_rnn.png
--------------------------------------------------------------------------------
/seminars/4/images/bilstm_crf_model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/bilstm_crf_model.png
--------------------------------------------------------------------------------
/seminars/4/images/dino.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/dino.jpg
--------------------------------------------------------------------------------
/seminars/4/images/dino.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/dino.png
--------------------------------------------------------------------------------
/seminars/4/images/dinos3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/dinos3.png
--------------------------------------------------------------------------------
/seminars/4/images/rnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/rnn.png
--------------------------------------------------------------------------------
/seminars/4/images/rnn_cell_backprop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/rnn_cell_backprop.png
--------------------------------------------------------------------------------
/seminars/4/images/rnn_step_forward.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/rnn_step_forward.png
--------------------------------------------------------------------------------
/seminars/4/images/understanding_lstms.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/understanding_lstms.jpg
--------------------------------------------------------------------------------
/seminars/4/images/word_representation_model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/4/images/word_representation_model.png
--------------------------------------------------------------------------------
/seminars/5/img/LDA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/LDA.png
--------------------------------------------------------------------------------
/seminars/5/img/artm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/artm.jpg
--------------------------------------------------------------------------------
/seminars/5/img/bow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/bow.png
--------------------------------------------------------------------------------
/seminars/5/img/ldavis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/ldavis.png
--------------------------------------------------------------------------------
/seminars/5/img/lsa.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/lsa.gif
--------------------------------------------------------------------------------
/seminars/5/img/matrix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/matrix.png
--------------------------------------------------------------------------------
/seminars/5/img/plsi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/plsi.png
--------------------------------------------------------------------------------
/seminars/5/img/svd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/5/img/svd.png
--------------------------------------------------------------------------------
/seminars/5/rus_stopwords.txt:
--------------------------------------------------------------------------------
1 | 0
2 | 1
3 | 2
4 | 3
5 | 4
6 | 5
7 | 6
8 | 7
9 | 8
10 | 9
11 | а
12 | ах
13 | б
14 | без
15 | безо
16 | более
17 | больше
18 | будем
19 | будет
20 | будете
21 | будешь
22 | будто
23 | буду
24 | будут
25 | будучи
26 | будь
27 | будьте
28 | бы
29 | был
30 | была
31 | были
32 | было
33 | быть
34 | в
35 | вам
36 | вами
37 | вас
38 | ваш
39 | ваше
40 | вдруг
41 | ведь
42 | весь
43 | весьма
44 | видеть
45 | видит
46 | вместе
47 | во
48 | восемь
49 | вот
50 | впрочем
51 | все
52 | всегда
53 | всего
54 | всей
55 | всем
56 | всеми
57 | всему
58 | всех
59 | всею
60 | всея
61 | вскоре
62 | всю
63 | вся
64 | всё
65 | всём
66 | вчера
67 | вы
68 | г
69 | где
70 | говорил
71 | говорила
72 | говорили
73 | говорит
74 | говорить
75 | д
76 | да
77 | даже
78 | два
79 | две
80 | двое
81 | двум
82 | двумя
83 | двух
84 | девять
85 | делал
86 | делала
87 | делали
88 | делать
89 | десять
90 | для
91 | до
92 | др
93 | другой
94 | думает
95 | думал
96 | думала
97 | думали
98 | думать
99 | е
100 | его
101 | ее
102 | ей
103 | ему
104 | емъ
105 | если
106 | есть
107 | еще
108 | ещё
109 | ею
110 | её
111 | ж
112 | же
113 | з
114 | за
115 | затем
116 | зачем
117 | здесь
118 | и
119 | из
120 | изо
121 | или
122 | им
123 | ими
124 | имъ
125 | иногда
126 | их
127 | к
128 | ка
129 | как
130 | какая
131 | какой
132 | кем
133 | ко
134 | когда
135 | кого
136 | коли
137 | коль
138 | ком
139 | кому
140 | конечно
141 | которая
142 | которого
143 | которое
144 | которой
145 | котором
146 | которому
147 | которою
148 | которые
149 | который
150 | который
151 | которым
152 | которыми
153 | которых
154 | кто
155 | куда
156 | л
157 | ли
158 | лучше
159 | м
160 | между
161 | меня
162 | мені
163 | млн
164 | млрд
165 | мне
166 | много
167 | мной
168 | мною
169 | мог
170 | моги
171 | могите
172 | могла
173 | могли
174 | могло
175 | могу
176 | могут
177 | мое
178 | моего
179 | моей
180 | моем
181 | моему
182 | моею
183 | можем
184 | может
185 | можете
186 | можешь
187 | можно
188 | мои
189 | моим
190 | моими
191 | моих
192 | мой
193 | мочь
194 | мою
195 | моя
196 | моё
197 | моём
198 | мы
199 | н
200 | на
201 | над
202 | надо
203 | наконец
204 | нам
205 | нами
206 | нас
207 | наш
208 | наша
209 | наше
210 | нашего
211 | нашей
212 | нашем
213 | нашему
214 | нашею
215 | наши
216 | нашим
217 | нашими
218 | наших
219 | нашою
220 | нашої
221 | нашу
222 | наші
223 | нашій
224 | нашім
225 | не
226 | него
227 | нее
228 | ней
229 | нельзя
230 | нем
231 | нему
232 | несколько
233 | нет
234 | нечего
235 | нею
236 | неё
237 | ни
238 | нибудь
239 | никогда
240 | ним
241 | ним
242 | ними
243 | них
244 | ничего
245 | но
246 | ноль
247 | ну
248 | нужно
249 | нём
250 | о
251 | об
252 | один
253 | одна
254 | однако
255 | одни
256 | одним
257 | одними
258 | одних
259 | одно
260 | одно
261 | одного
262 | одной
263 | одном
264 | одному
265 | одною
266 | одну
267 | одну
268 | около
269 | он
270 | она
271 | оне
272 | они
273 | оно
274 | опять
275 | от
276 | ответил
277 | ответила
278 | ответили
279 | ответить
280 | отвечает
281 | отвечал
282 | отвечала
283 | отвечали
284 | отвечать
285 | ох
286 | очень
287 | п
288 | перед
289 | по
290 | под
291 | после
292 | потом
293 | потому
294 | почему
295 | почти
296 | при
297 | про
298 | пятеро
299 | пять
300 | р
301 | раз
302 | разве
303 | руб
304 | с
305 | сам
306 | сама
307 | сами
308 | самим
309 | самими
310 | самих
311 | само
312 | самого
313 | самом
314 | самому
315 | саму
316 | свое
317 | своего
318 | своей
319 | своем
320 | своему
321 | своею
322 | свои
323 | своим
324 | своими
325 | своих
326 | свой
327 | свою
328 | своя
329 | своё
330 | своём
331 | себе
332 | себя
333 | сегодня
334 | сей
335 | сейчас
336 | семеро
337 | семь
338 | сказал
339 | сказала
340 | сказали
341 | сказать
342 | скоро
343 | со
344 | собой
345 | собою
346 | совсем
347 | спросил
348 | спросила
349 | спросили
350 | спросить
351 | стал
352 | стала
353 | стали
354 | стать
355 | съ
356 | т
357 | та
358 | так
359 | такая
360 | также
361 | такие
362 | таким
363 | такими
364 | таких
365 | такого
366 | такое
367 | такой
368 | таком
369 | такому
370 | такою
371 | такую
372 | там
373 | твое
374 | твои
375 | твой
376 | твоя
377 | твоё
378 | те
379 | тебе
380 | тебя
381 | тем
382 | теми
383 | теперь
384 | тех
385 | теє
386 | то
387 | тобой
388 | тобою
389 | тогда
390 | того
391 | тоже
392 | той
393 | только
394 | том
395 | тому
396 | тот
397 | тотчас
398 | тою
399 | три
400 | трое
401 | ту
402 | тут
403 | ты
404 | тыс
405 | ті
406 | тією
407 | тієї
408 | тії
409 | у
410 | увидел
411 | увидела
412 | увидели
413 | увидеть
414 | уж
415 | уже
416 | ул
417 | ф
418 | х
419 | хорошо
420 | хотел
421 | хотела
422 | хотели
423 | хотеть
424 | хоть
425 | хотя
426 | хочет
427 | ц
428 | ч
429 | чего
430 | чем
431 | чему
432 | через
433 | четверо
434 | четыре
435 | что
436 | чтоб
437 | чтобы
438 | чуть
439 | чём
440 | ш
441 | шестеро
442 | шесть
443 | щ
444 | ъ
445 | ы
446 | ь
447 | э
448 | эта
449 | эти
450 | этим
451 | этими
452 | этих
453 | это
454 | этого
455 | этой
456 | этом
457 | этому
458 | этот
459 | этою
460 | эту
461 | ю
462 | я
463 | я
464 | як
465 | ё
--------------------------------------------------------------------------------
/seminars/8/constituency_parsing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/8/constituency_parsing.png
--------------------------------------------------------------------------------
/seminars/8/recursiveNN.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/8/recursiveNN.jpg
--------------------------------------------------------------------------------
/seminars/8/recursiveNN_formula.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/8/recursiveNN_formula.jpg
--------------------------------------------------------------------------------
/seminars/8/rus_tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/8/rus_tree.png
--------------------------------------------------------------------------------
/seminars/8/sem8_syntax.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Depencency parsing\n",
8 | "(парсинг зависимостей)\n",
9 | "\n",
10 | "### Что это?\n",
11 | "\n",
12 | "* наша цель -- представить предложение естественного языка в виде дерева\n",
13 | "* слова предложения -- вершины; *зависимости (dependencies)* между ними -- рёбра\n",
14 | "* зависимости могут быть разными: например, субъект глагола, объект глагола, прилагательное-модификатор, и так далее\n",
15 | "\n",
16 | "### Формат\n",
17 | "\n",
18 | "Существует несколько форматов записи деревьев зависимостей, но самый популярный и общеиспользуемый -- [CoNLL-U](http://universaldependencies.org/format.html).
\n",
19 | "Как это выглядит (пример из [русского Universal Dependency трибанка](https://github.com/UniversalDependencies/UD_Russian-SynTagRus)):"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 1,
25 | "metadata": {},
26 | "outputs": [],
27 | "source": [
28 | "my_example = \"\"\"\n",
29 | "# sent_id = 2003Armeniya.xml_138\n",
30 | "# text = Перспективы развития сферы высоких технологий.\n",
31 | "1\tПерспективы\tперспектива\tNOUN\t_\tAnimacy=Inan|Case=Nom|Gender=Fem|Number=Plur\t0\tROOT\t0:root\t_\n",
32 | "2\tразвития\tразвитие\tNOUN\t_\tAnimacy=Inan|Case=Gen|Gender=Neut|Number=Sing\t1\tnmod\t1:nmod\t_\n",
33 | "3\tсферы\tсфера\tNOUN\t_\tAnimacy=Inan|Case=Gen|Gender=Fem|Number=Sing\t2\tnmod\t2:nmod\t_\n",
34 | "4\tвысоких\tвысокий\tADJ\t_\tCase=Gen|Degree=Pos|Number=Plur\t5\tamod\t5:amod\t_\n",
35 | "5\tтехнологий\tтехнология\tNOUN\t_\tAnimacy=Inan|Case=Gen|Gender=Fem|Number=Plur\t3\tnmod\t3:nmod\tSpaceAfter=No\n",
36 | "6\t.\t.\tPUNCT\t_\t_\t1\tpunct\t1:punct\t_\n",
37 | "\"\"\""
38 | ]
39 | },
40 | {
41 | "cell_type": "markdown",
42 | "metadata": {},
43 | "source": [
44 | "Комментарии + таблица c 9 колонками (разделители табы):\n",
45 | "* ID\n",
46 | "* FORM: токен\n",
47 | "* LEMMA: начальная форма\n",
48 | "* UPOS: универсальная часть речи\n",
49 | "* XPOS: лингво-специфичная часть речи\n",
50 | "* FEATS: морфологическая информация: падеж, род, число etc\n",
51 | "* HEAD: id ролителя\n",
52 | "* DEPREL: тип зависимости, то есть отношение к токену-родителю\n",
53 | "* DEPS: альтернативный подграф (не будем углубляться :))\n",
54 | "* MISC: всё остальное\n",
55 | "\n",
56 | "Отсутствующие данные представляются с помощью `_`. Больше подробностей про формат -- в [официальной документаци](http://universaldependencies.org/format.html).
\n",
57 | "User-friendly визуализация: \n",
58 | "\n",
59 | "Отрытый инструмент для визуализации, ручной разметки и конвертации в другие форматы: UD Annotatrix. [Online-интерфейс](https://universal-dependencies.linghub.net/annotatrix), [репозиторий](https://github.com/jonorthwash/ud-annotatrix).\n",
60 | "\n",
61 | "Трибанк -- много таких предложений. Обычно они разделяются двумя переносами строки.\n",
62 | "### Как считывать данные в питоне\n",
63 | "\n",
64 | "Используем библиотеку [conllu](https://github.com/EmilStenstrom/conllu)."
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": 2,
70 | "metadata": {},
71 | "outputs": [
72 | {
73 | "name": "stdout",
74 | "output_type": "stream",
75 | "text": [
76 | "Collecting conllu\n",
77 | " Downloading https://files.pythonhosted.org/packages/9e/34/ddfbf22e7477a75ca609d60a831452439383e4ab61bed2b5a1b83d1eef5b/conllu-2.0-py2.py3-none-any.whl\n",
78 | "Installing collected packages: conllu\n",
79 | "Successfully installed conllu-2.0\n",
80 | "\u001b[33mYou are using pip version 8.1.1, however version 19.2.3 is available.\n",
81 | "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n"
82 | ]
83 | }
84 | ],
85 | "source": [
86 | "!pip3 install conllu"
87 | ]
88 | },
89 | {
90 | "cell_type": "code",
91 | "execution_count": 6,
92 | "metadata": {},
93 | "outputs": [],
94 | "source": [
95 | "from conllu import parse"
96 | ]
97 | },
98 | {
99 | "cell_type": "code",
100 | "execution_count": 3,
101 | "metadata": {},
102 | "outputs": [
103 | {
104 | "name": "stdout",
105 | "output_type": "stream",
106 | "text": [
107 | "Help on function parse in module conllu:\n",
108 | "\n",
109 | "parse(data, fields=None, field_parsers=None)\n",
110 | "\n"
111 | ]
112 | }
113 | ],
114 | "source": [
115 | "help(parse)"
116 | ]
117 | },
118 | {
119 | "cell_type": "code",
120 | "execution_count": 4,
121 | "metadata": {},
122 | "outputs": [
123 | {
124 | "data": {
125 | "text/plain": [
126 | "OrderedDict([('id', 1),\n",
127 | " ('form', 'Перспективы'),\n",
128 | " ('lemma', 'перспектива'),\n",
129 | " ('upostag', 'NOUN'),\n",
130 | " ('xpostag', None),\n",
131 | " ('feats',\n",
132 | " OrderedDict([('Animacy', 'Inan'),\n",
133 | " ('Case', 'Nom'),\n",
134 | " ('Gender', 'Fem'),\n",
135 | " ('Number', 'Plur')])),\n",
136 | " ('head', 0),\n",
137 | " ('deprel', 'ROOT'),\n",
138 | " ('deps', '0:root'),\n",
139 | " ('misc', None)])"
140 | ]
141 | },
142 | "execution_count": 4,
143 | "metadata": {},
144 | "output_type": "execute_result"
145 | }
146 | ],
147 | "source": [
148 | "sentences = parse(my_example)\n",
149 | "sentence = sentences[0]\n",
150 | "sentence[0]"
151 | ]
152 | },
153 | {
154 | "cell_type": "code",
155 | "execution_count": 5,
156 | "metadata": {},
157 | "outputs": [
158 | {
159 | "data": {
160 | "text/plain": [
161 | "OrderedDict([('id', 6),\n",
162 | " ('form', '.'),\n",
163 | " ('lemma', '.'),\n",
164 | " ('upostag', 'PUNCT'),\n",
165 | " ('xpostag', None),\n",
166 | " ('feats', None),\n",
167 | " ('head', 1),\n",
168 | " ('deprel', 'punct'),\n",
169 | " ('deps', [('punct', 1)]),\n",
170 | " ('misc', None)])"
171 | ]
172 | },
173 | "execution_count": 5,
174 | "metadata": {},
175 | "output_type": "execute_result"
176 | }
177 | ],
178 | "source": [
179 | "sentence[-1]"
180 | ]
181 | },
182 | {
183 | "cell_type": "markdown",
184 | "metadata": {},
185 | "source": [
186 | "## Визуализация\n",
187 | "\n",
188 | "В nltk есть DependencyGraph, который умеет рисовать деревья (и ещё многое другое). Для того, чтобы визуализация работала корректно, ему нужна зависимость: graphviz."
189 | ]
190 | },
191 | {
192 | "cell_type": "code",
193 | "execution_count": null,
194 | "metadata": {},
195 | "outputs": [],
196 | "source": [
197 | "!apt-get install graphviz\n",
198 | "!pip install graphviz"
199 | ]
200 | },
201 | {
202 | "cell_type": "code",
203 | "execution_count": 7,
204 | "metadata": {},
205 | "outputs": [],
206 | "source": [
207 | "from nltk import DependencyGraph"
208 | ]
209 | },
210 | {
211 | "cell_type": "markdown",
212 | "metadata": {},
213 | "source": [
214 | "В отличие от `conllu`, `DependencyGraph` не справляется с комментариями, поэтому придётся их убрать. Кроме того ему обязательно нужен `deprel` *ROOT* в верхнем регистре, иначе он не находит корень."
215 | ]
216 | },
217 | {
218 | "cell_type": "code",
219 | "execution_count": 8,
220 | "metadata": {},
221 | "outputs": [],
222 | "source": [
223 | "sents = []\n",
224 | "for sent in my_example.split('\\n\\n'):\n",
225 | " # убираем коменты\n",
226 | " sent = '\\n'.join([line for line in sent.split('\\n') if not line.startswith('#')])\n",
227 | " # заменяем deprel для root\n",
228 | " sent = sent.replace('\\troot\\t', '\\tROOT\\t')\n",
229 | " sents.append(sent)"
230 | ]
231 | },
232 | {
233 | "cell_type": "code",
234 | "execution_count": 9,
235 | "metadata": {},
236 | "outputs": [
237 | {
238 | "data": {
239 | "image/svg+xml": [
240 | "\n",
241 | "\n",
243 | "\n",
245 | "\n",
246 | "\n"
317 | ],
318 | "text/plain": [
319 | ""
320 | ]
321 | },
322 | "execution_count": 9,
323 | "metadata": {},
324 | "output_type": "execute_result"
325 | }
326 | ],
327 | "source": [
328 | "graph = DependencyGraph(tree_str=sents[0])\n",
329 | "graph"
330 | ]
331 | },
332 | {
333 | "cell_type": "code",
334 | "execution_count": 10,
335 | "metadata": {},
336 | "outputs": [
337 | {
338 | "name": "stdout",
339 | "output_type": "stream",
340 | "text": [
341 | " Перспективы \n",
342 | " _______|__________ \n",
343 | " | развития \n",
344 | " | | \n",
345 | " | сферы \n",
346 | " | | \n",
347 | " | технологий\n",
348 | " | | \n",
349 | " . высоких \n",
350 | "\n",
351 | "None\n"
352 | ]
353 | }
354 | ],
355 | "source": [
356 | "tree = graph.tree()\n",
357 | "print(tree.pretty_print())"
358 | ]
359 | },
360 | {
361 | "cell_type": "markdown",
362 | "metadata": {},
363 | "source": [
364 | "## UDPipe\n",
365 | "\n",
366 | "Есть разные инструменты для парсинга зависимостей. Сегодня мы посмотрим на [UDPipe](http://ufal.mff.cuni.cz/udpipe). UDPipe умеет парсить текст с помощью готовых моделей (которые можно скачать [здесь](https://github.com/jwijffels/udpipe.models.ud.2.0/tree/master/inst/udpipe-ud-2.0-170801)) и обучать модели на своих трибанках.\n",
367 | "\n",
368 | "Собственно, в UDPipe есть три вида моделей:\n",
369 | "* токенизатор (разделить текст на предложения, предложения на токены, сделать заготовку для CoNLL-U)\n",
370 | "* тэггер (лемматизировать, разметить части речи)\n",
371 | "* сам парсер (проставить каждому токену `head` и `deprel`)\n",
372 | "\n",
373 | "Мы сегодня не будем обучать новых моделей (это слишком долго), а используем готовую модель для русского."
374 | ]
375 | },
376 | {
377 | "cell_type": "markdown",
378 | "metadata": {},
379 | "source": [
380 | "### The Python binding\n",
381 | "\n",
382 | "У udpipe есть питоновская обвязка. Она довольно [плохо задокументирована](https://pypi.org/project/ufal.udpipe/), но зато можно использовать прямо в питоне :)"
383 | ]
384 | },
385 | {
386 | "cell_type": "code",
387 | "execution_count": 1,
388 | "metadata": {},
389 | "outputs": [
390 | {
391 | "name": "stdout",
392 | "output_type": "stream",
393 | "text": [
394 | "Requirement already satisfied: ufal.udpipe in /usr/local/lib/python3.5/dist-packages (1.2.0.1)\n",
395 | "\u001b[33mYou are using pip version 18.0, however version 18.1 is available.\n",
396 | "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n"
397 | ]
398 | }
399 | ],
400 | "source": [
401 | "!pip install ufal.udpipe"
402 | ]
403 | },
404 | {
405 | "cell_type": "code",
406 | "execution_count": 11,
407 | "metadata": {},
408 | "outputs": [],
409 | "source": [
410 | "from ufal.udpipe import Model, Pipeline"
411 | ]
412 | },
413 | {
414 | "cell_type": "code",
415 | "execution_count": 12,
416 | "metadata": {},
417 | "outputs": [
418 | {
419 | "name": "stdout",
420 | "output_type": "stream",
421 | "text": [
422 | "--2019-09-29 23:23:05-- https://github.com/jwijffels/udpipe.models.ud.2.0/raw/master/inst/udpipe-ud-2.0-170801/russian-ud-2.0-170801.udpipe\n",
423 | "Resolving github.com (github.com)... 140.82.118.3\n",
424 | "Connecting to github.com (github.com)|140.82.118.3|:443... connected.\n",
425 | "HTTP request sent, awaiting response... 302 Found\n",
426 | "Location: https://raw.githubusercontent.com/jwijffels/udpipe.models.ud.2.0/master/inst/udpipe-ud-2.0-170801/russian-ud-2.0-170801.udpipe [following]\n",
427 | "--2019-09-29 23:23:06-- https://raw.githubusercontent.com/jwijffels/udpipe.models.ud.2.0/master/inst/udpipe-ud-2.0-170801/russian-ud-2.0-170801.udpipe\n",
428 | "Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.244.133\n",
429 | "Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.244.133|:443... connected.\n",
430 | "HTTP request sent, awaiting response... 200 OK\n",
431 | "Length: 13265262 (13M) [application/octet-stream]\n",
432 | "Saving to: ‘russian-ud-2.0-170801.udpipe’\n",
433 | "\n",
434 | "russian-ud-2.0-1708 100%[===================>] 12,65M 12,7MB/s in 1,0s \n",
435 | "\n",
436 | "2019-09-29 23:23:08 (12,7 MB/s) - ‘russian-ud-2.0-170801.udpipe’ saved [13265262/13265262]\n",
437 | "\n"
438 | ]
439 | }
440 | ],
441 | "source": [
442 | "!wget https://github.com/jwijffels/udpipe.models.ud.2.0/raw/master/inst/udpipe-ud-2.0-170801/russian-ud-2.0-170801.udpipe"
443 | ]
444 | },
445 | {
446 | "cell_type": "code",
447 | "execution_count": 13,
448 | "metadata": {},
449 | "outputs": [],
450 | "source": [
451 | "model = Model.load(\"russian-ud-2.0-170801.udpipe\") # path to the model"
452 | ]
453 | },
454 | {
455 | "cell_type": "code",
456 | "execution_count": 14,
457 | "metadata": {},
458 | "outputs": [
459 | {
460 | "data": {
461 | "text/plain": [
462 | ""
463 | ]
464 | },
465 | "execution_count": 14,
466 | "metadata": {},
467 | "output_type": "execute_result"
468 | }
469 | ],
470 | "source": [
471 | "# если успех, должно быть так (model != None)\n",
472 | "model"
473 | ]
474 | },
475 | {
476 | "cell_type": "code",
477 | "execution_count": 15,
478 | "metadata": {},
479 | "outputs": [
480 | {
481 | "name": "stdout",
482 | "output_type": "stream",
483 | "text": [
484 | "# newdoc\n",
485 | "# newpar\n",
486 | "# sent_id = 1\n",
487 | "# text = Если бы мне платили каждый раз.\n",
488 | "1\tЕсли\tЕСЛИ\tSCONJ\tIN\t_\t4\tmark\t_\t_\n",
489 | "2\tбы\tБЫ\tPART\tRP\t_\t4\tdiscourse\t_\t_\n",
490 | "3\tмне\tЯ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=1\t4\tiobj\t_\t_\n",
491 | "4\tплатили\tПЛАТИТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Plur|Tense=Past|VerbForm=Fin\t0\troot\t_\t_\n",
492 | "5\tкаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t6\tamod\t_\t_\n",
493 | "6\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t4\tadvmod\t_\tSpaceAfter=No\n",
494 | "7\t.\t.\tPUNCT\t.\t_\t4\tpunct\t_\t_\n",
495 | "\n",
496 | "# sent_id = 2\n",
497 | "# text = Каждый раз, когда я думаю о тебе.\n",
498 | "1\tКаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t2\tamod\t_\t_\n",
499 | "2\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t6\tadvmod\t_\tSpaceAfter=No\n",
500 | "3\t,\t,\tPUNCT\t,\t_\t6\tpunct\t_\t_\n",
501 | "4\tкогда\tКОГДА\tADV\tWRB\t_\t6\tadvmod\t_\t_\n",
502 | "5\tя\tЯ\tPRON\tPRP\tCase=Nom|Number=Sing|Person=1\t6\tnsubj\t_\t_\n",
503 | "6\tдумаю\tдУМАТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin\t0\troot\t_\t_\n",
504 | "7\tо\tО\tADP\tIN\t_\t8\tcase\t_\t_\n",
505 | "8\tтебе\tТЫ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=2\t6\tobl\t_\tSpaceAfter=No\n",
506 | "9\t.\t.\tPUNCT\t.\t_\t6\tpunct\t_\tSpacesAfter=\\n\n",
507 | "\n",
508 | "\n"
509 | ]
510 | }
511 | ],
512 | "source": [
513 | "pipeline = Pipeline(model, 'generic_tokenizer', '', '', '')\n",
514 | "example = \"Если бы мне платили каждый раз. Каждый раз, когда я думаю о тебе.\"\n",
515 | "parsed = pipeline.process(example)\n",
516 | "print(parsed)"
517 | ]
518 | },
519 | {
520 | "cell_type": "markdown",
521 | "metadata": {},
522 | "source": [
523 | "Как видим, UDPipe и токенизировал, и лематизировал текст, сделал POS-tagging и, собственно, синтаксический парсинг."
524 | ]
525 | },
526 | {
527 | "cell_type": "markdown",
528 | "metadata": {},
529 | "source": [
530 | "### Command line interface\n",
531 | "\n",
532 | "Но с обвязкой бывают проблемы, и вообще довольно удобно пользоваться прекомпилированной утилитой `udpipe` из шелла."
533 | ]
534 | },
535 | {
536 | "cell_type": "code",
537 | "execution_count": 22,
538 | "metadata": {},
539 | "outputs": [
540 | {
541 | "name": "stdout",
542 | "output_type": "stream",
543 | "text": [
544 | "--2019-09-29 23:31:16-- https://github.com/ufal/udpipe/releases/download/v1.2.0/udpipe-1.2.0-bin.zip\n",
545 | "Resolving github.com (github.com)... 140.82.118.3\n",
546 | "Connecting to github.com (github.com)|140.82.118.3|:443... connected.\n",
547 | "HTTP request sent, awaiting response... 302 Found\n",
548 | "Location: https://github-production-release-asset-2e65be.s3.amazonaws.com/50672597/a24cacd8-77c6-11e7-8f6e-e9de8ca37f48?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190929T203116Z&X-Amz-Expires=300&X-Amz-Signature=844d153d7dc66e51f2aa43d0ee199e4a5d8f6b7e2755e3f50fc136597f8111c9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dudpipe-1.2.0-bin.zip&response-content-type=application%2Foctet-stream [following]\n",
549 | "--2019-09-29 23:31:17-- https://github-production-release-asset-2e65be.s3.amazonaws.com/50672597/a24cacd8-77c6-11e7-8f6e-e9de8ca37f48?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190929T203116Z&X-Amz-Expires=300&X-Amz-Signature=844d153d7dc66e51f2aa43d0ee199e4a5d8f6b7e2755e3f50fc136597f8111c9&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Dudpipe-1.2.0-bin.zip&response-content-type=application%2Foctet-stream\n",
550 | "Resolving github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)... 52.216.170.107\n",
551 | "Connecting to github-production-release-asset-2e65be.s3.amazonaws.com (github-production-release-asset-2e65be.s3.amazonaws.com)|52.216.170.107|:443... connected.\n",
552 | "HTTP request sent, awaiting response... 200 OK\n",
553 | "Length: 12644197 (12M) [application/octet-stream]\n",
554 | "Saving to: ‘udpipe-1.2.0-bin.zip’\n",
555 | "\n",
556 | "udpipe-1.2.0-bin.zi 100%[===================>] 12,06M 3,49MB/s in 3,7s \n",
557 | "\n",
558 | "2019-09-29 23:31:21 (3,22 MB/s) - ‘udpipe-1.2.0-bin.zip’ saved [12644197/12644197]\n",
559 | "\n"
560 | ]
561 | }
562 | ],
563 | "source": [
564 | "!wget https://github.com/ufal/udpipe/releases/download/v1.2.0/udpipe-1.2.0-bin.zip"
565 | ]
566 | },
567 | {
568 | "cell_type": "code",
569 | "execution_count": 26,
570 | "metadata": {},
571 | "outputs": [],
572 | "source": [
573 | "# !unzip udpipe-1.2.0-bin.zip"
574 | ]
575 | },
576 | {
577 | "cell_type": "markdown",
578 | "metadata": {},
579 | "source": [
580 | "Внутри бинарники для всех популярных ОС, выбираем свою. У меня путь к бинарнику такой: `udpipe-1.2.0-bin/bin-linux64`.\n",
581 | "\n",
582 | "Синтаксис:"
583 | ]
584 | },
585 | {
586 | "cell_type": "code",
587 | "execution_count": 30,
588 | "metadata": {},
589 | "outputs": [
590 | {
591 | "name": "stdout",
592 | "output_type": "stream",
593 | "text": [
594 | "Usage: udpipe-1.2.0-bin/bin-linux64/udpipe [running_opts] model_file [input_files]\r\n",
595 | " udpipe-1.2.0-bin/bin-linux64/udpipe --train [training_opts] model_file [input_files]\r\n",
596 | " udpipe-1.2.0-bin/bin-linux64/udpipe --detokenize [detokenize_opts] raw_text_file [input_files]\r\n",
597 | "Running opts: --accuracy (measure accuracy only)\r\n",
598 | " --input=[conllu|generic_tokenizer|horizontal|vertical]\r\n",
599 | " --immediate (process sentences immediately during loading)\r\n",
600 | " --outfile=output file template\r\n",
601 | " --output=[conllu|epe|matxin|horizontal|plaintext|vertical]\r\n",
602 | " --tokenize (perform tokenization)\r\n",
603 | " --tokenizer=tokenizer options, implies --tokenize\r\n",
604 | " --tag (perform tagging)\r\n",
605 | " --tagger=tagger options, implies --tag\r\n",
606 | " --parse (perform parsing)\r\n",
607 | " --parser=parser options, implies --parse\r\n",
608 | "Training opts: --method=[morphodita_parsito] which method to use\r\n",
609 | " --heldout=heldout data file name\r\n",
610 | " --tokenizer=tokenizer options\r\n",
611 | " --tagger=tagger options\r\n",
612 | " --parser=parser options\r\n",
613 | "Detokenize opts: --outfile=output file template\r\n",
614 | "Generic opts: --version\r\n",
615 | " --help\r\n"
616 | ]
617 | }
618 | ],
619 | "source": [
620 | "! udpipe-1.2.0-bin/bin-linux64/udpipe --help"
621 | ]
622 | },
623 | {
624 | "cell_type": "markdown",
625 | "metadata": {},
626 | "source": [
627 | "Типичная команда для парсинга будет выглядеть так:"
628 | ]
629 | },
630 | {
631 | "cell_type": "code",
632 | "execution_count": 33,
633 | "metadata": {},
634 | "outputs": [
635 | {
636 | "name": "stdout",
637 | "output_type": "stream",
638 | "text": [
639 | "Loading UDPipe model: done.\n",
640 | "# newdoc id = example.txt\n",
641 | "# newpar\n",
642 | "# sent_id = 1\n",
643 | "# text = Если бы мне платили каждый раз.\n",
644 | "1\tЕсли\tЕСЛИ\tSCONJ\tIN\t_\t4\tmark\t_\t_\n",
645 | "2\tбы\tБЫ\tPART\tRP\t_\t4\tdiscourse\t_\t_\n",
646 | "3\tмне\tЯ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=1\t4\tiobj\t_\t_\n",
647 | "4\tплатили\tПЛАТИТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Plur|Tense=Past|VerbForm=Fin\t0\troot\t_\t_\n",
648 | "5\tкаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t6\tamod\t_\t_\n",
649 | "6\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t4\tadvmod\t_\tSpaceAfter=No\n",
650 | "7\t.\t.\tPUNCT\t.\t_\t4\tpunct\t_\t_\n",
651 | "\n",
652 | "# sent_id = 2\n",
653 | "# text = Каждый раз, когда я думаю о тебе.\n",
654 | "1\tКаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t2\tamod\t_\t_\n",
655 | "2\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t6\tadvmod\t_\tSpaceAfter=No\n",
656 | "3\t,\t,\tPUNCT\t,\t_\t6\tpunct\t_\t_\n",
657 | "4\tкогда\tКОГДА\tADV\tWRB\t_\t6\tadvmod\t_\t_\n",
658 | "5\tя\tЯ\tPRON\tPRP\tCase=Nom|Number=Sing|Person=1\t6\tnsubj\t_\t_\n",
659 | "6\tдумаю\tдУМАТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin\t0\troot\t_\t_\n",
660 | "7\tо\tО\tADP\tIN\t_\t8\tcase\t_\t_\n",
661 | "8\tтебе\tТЫ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=2\t6\tobl\t_\tSpaceAfter=No\n",
662 | "9\t.\t.\tPUNCT\t.\t_\t6\tpunct\t_\tSpacesAfter=\\n\n",
663 | "\n"
664 | ]
665 | }
666 | ],
667 | "source": [
668 | "with open('example.txt', 'w') as f:\n",
669 | " f.write(example)\n",
670 | "\n",
671 | "! udpipe-1.2.0-bin/bin-linux64/udpipe --tokenize --tag --parse\\\n",
672 | " russian-ud-2.0-170801.udpipe example.txt > parsed_example.conllu\n",
673 | "! cat parsed_example.conllu"
674 | ]
675 | },
676 | {
677 | "cell_type": "markdown",
678 | "metadata": {},
679 | "source": [
680 | "Если нас интересует только тэггинг:"
681 | ]
682 | },
683 | {
684 | "cell_type": "code",
685 | "execution_count": 18,
686 | "metadata": {},
687 | "outputs": [
688 | {
689 | "name": "stdout",
690 | "output_type": "stream",
691 | "text": [
692 | "Loading UDPipe model: done.\n",
693 | "# newdoc id = example.txt\n",
694 | "# newpar\n",
695 | "# sent_id = 1\n",
696 | "# text = Если бы мне платили каждый раз.\n",
697 | "1\tЕсли\tЕСЛИ\tSCONJ\tIN\t_\t_\t_\t_\t_\n",
698 | "2\tбы\tБЫ\tPART\tRP\t_\t_\t_\t_\t_\n",
699 | "3\tмне\tЯ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=1\t_\t_\t_\t_\n",
700 | "4\tплатили\tПЛАТИТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Plur|Tense=Past|VerbForm=Fin\t_\t_\t_\t_\n",
701 | "5\tкаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t_\t_\t_\t_\n",
702 | "6\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t_\t_\t_\tSpaceAfter=No\n",
703 | "7\t.\t.\tPUNCT\t.\t_\t_\t_\t_\t_\n",
704 | "\n",
705 | "# sent_id = 2\n",
706 | "# text = Каждый раз, когда я думаю о тебе.\n",
707 | "1\tКаждый\tКАЖДЫЙ\tDET\tDT\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t_\t_\t_\t_\n",
708 | "2\tраз\tРАЗ\tNOUN\tNN\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing\t_\t_\t_\tSpaceAfter=No\n",
709 | "3\t,\t,\tPUNCT\t,\t_\t_\t_\t_\t_\n",
710 | "4\tкогда\tКОГДА\tADV\tWRB\t_\t_\t_\t_\t_\n",
711 | "5\tя\tЯ\tPRON\tPRP\tCase=Nom|Number=Sing|Person=1\t_\t_\t_\t_\n",
712 | "6\tдумаю\tдУМАТЬ\tVERB\tVBC\tAspect=Imp|Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin\t_\t_\t_\t_\n",
713 | "7\tо\tО\tADP\tIN\t_\t_\t_\t_\t_\n",
714 | "8\tтебе\tТЫ\tPRON\tPRP\tCase=Dat|Number=Sing|Person=2\t_\t_\t_\tSpaceAfter=No\n",
715 | "9\t.\t.\tPUNCT\t.\t_\t_\t_\t_\tSpacesAfter=\\n\n",
716 | "\n"
717 | ]
718 | }
719 | ],
720 | "source": [
721 | "with open('example.txt', 'w') as f:\n",
722 | " f.write(example)\n",
723 | "\n",
724 | "! udpipe-1.2.0-bin/bin-linux64/udpipe --tokenize --tag\\\n",
725 | " russian-ud-2.0-170801.udpipe example.txt > tagged_example.conllu\n",
726 | "! cat tagged_example.conllu"
727 | ]
728 | },
729 | {
730 | "cell_type": "markdown",
731 | "metadata": {},
732 | "source": [
733 | "(Ну а потом снова считываем проанализированные предложения питоном).\n",
734 | "\n",
735 | "Вот два способа работать с UDPipe. Choose your fighter! "
736 | ]
737 | },
738 | {
739 | "cell_type": "markdown",
740 | "metadata": {},
741 | "source": [
742 | "#### Задание\n",
743 | "\n",
744 | "Напишите функцию, которая проверяет, не состоит ли предложение из большого числа однородных предложений."
745 | ]
746 | },
747 | {
748 | "cell_type": "code",
749 | "execution_count": null,
750 | "metadata": {},
751 | "outputs": [],
752 | "source": []
753 | },
754 | {
755 | "cell_type": "markdown",
756 | "metadata": {},
757 | "source": [
758 | "## SVO-triples\n",
759 | "\n",
760 | "С помощью синтекстического парсинга можно извлекать из предложений тройки субъект-объект-глагол, которые можно использовать для извлечения информации из текста. "
761 | ]
762 | },
763 | {
764 | "cell_type": "code",
765 | "execution_count": 34,
766 | "metadata": {},
767 | "outputs": [],
768 | "source": [
769 | "sent = \"\"\"1\tСобянин\t_\tNOUN\t_\tAnimacy=Anim|Case=Nom|Gender=Masc|Number=Sing|fPOS=NOUN++\t2\tnsubj\t_\t_\n",
770 | "2\tоткрыл\t_\tVERB\t_\tAspect=Perf|Gender=Masc|Mood=Ind|Number=Sing|Tense=Past|VerbForm=Fin|Voice=Act|fPOS=VERB++\t0\tROOT\t_\t_\n",
771 | "3\tновый\t_\tADJ\t_\tAnimacy=Inan|Case=Acc|Degree=Pos|Gender=Masc|Number=Sing|fPOS=ADJ++\t4\tamod\t_\t_\n",
772 | "4\tпарк\t_\tNOUN\t_\tAnimacy=Inan|Case=Acc|Gender=Masc|Number=Sing|fPOS=NOUN++\t2\tdobj\t_\t_\n",
773 | "5\tи\t_\tCONJ\t_\tfPOS=CONJ++\t4\tcc\t_\t_\n",
774 | "6\tдетскую\t_\tADJ\t_\tCase=Acc|Degree=Pos|Gender=Fem|Number=Sing|fPOS=ADJ++\t7\tamod\t_\t_\n",
775 | "7\tплощадку\t_\tNOUN\t_\tAnimacy=Inan|Case=Acc|Gender=Fem|Number=Sing|fPOS=NOUN++\t4\tconj\t_\t_\n",
776 | "8\t.\t_\tPUNCT\t.\tfPOS=PUNCT++.\t2\tpunct\t_\t_\"\"\""
777 | ]
778 | },
779 | {
780 | "cell_type": "markdown",
781 | "metadata": {},
782 | "source": [
783 | "Тройки слово-слово-связь:"
784 | ]
785 | },
786 | {
787 | "cell_type": "code",
788 | "execution_count": 37,
789 | "metadata": {},
790 | "outputs": [
791 | {
792 | "data": {
793 | "text/plain": [
794 | "[(('открыл', 'VERB'), 'nsubj', ('Собянин', 'NOUN')),\n",
795 | " (('открыл', 'VERB'), 'dobj', ('парк', 'NOUN')),\n",
796 | " (('парк', 'NOUN'), 'amod', ('новый', 'ADJ')),\n",
797 | " (('парк', 'NOUN'), 'cc', ('и', 'CONJ')),\n",
798 | " (('парк', 'NOUN'), 'conj', ('площадку', 'NOUN')),\n",
799 | " (('площадку', 'NOUN'), 'amod', ('детскую', 'ADJ')),\n",
800 | " (('открыл', 'VERB'), 'punct', ('.', 'PUNCT'))]"
801 | ]
802 | },
803 | "execution_count": 37,
804 | "metadata": {},
805 | "output_type": "execute_result"
806 | }
807 | ],
808 | "source": [
809 | "graph = DependencyGraph(tree_str=sent)\n",
810 | "list(graph.triples())"
811 | ]
812 | },
813 | {
814 | "cell_type": "markdown",
815 | "metadata": {},
816 | "source": [
817 | "Тройки субьект-объект-глагол:"
818 | ]
819 | },
820 | {
821 | "cell_type": "code",
822 | "execution_count": 39,
823 | "metadata": {},
824 | "outputs": [
825 | {
826 | "name": "stdout",
827 | "output_type": "stream",
828 | "text": [
829 | "{'открыл': {'obj': 'парк', 'subj': 'Собянин'}}\n"
830 | ]
831 | }
832 | ],
833 | "source": [
834 | "def get_sov(sent):\n",
835 | " graph = DependencyGraph(tree_str=sent)\n",
836 | " sov = {}\n",
837 | " for triple in graph.triples():\n",
838 | " if triple:\n",
839 | " if triple[0][1] == 'VERB':\n",
840 | " sov[triple[0][0]] = {'subj':'','obj':''}\n",
841 | " for triple in graph.triples():\n",
842 | " if triple:\n",
843 | " if triple[1] == 'nsubj':\n",
844 | " if triple[0][1] == 'VERB':\n",
845 | " sov[triple[0][0]]['subj'] = triple[2][0]\n",
846 | " if triple[1] == 'dobj':\n",
847 | " if triple[0][1] == 'VERB':\n",
848 | " sov[triple[0][0]]['obj'] = triple[2][0]\n",
849 | " return sov\n",
850 | "\n",
851 | "sov = get_sov(sent)\n",
852 | "print(sov)"
853 | ]
854 | },
855 | {
856 | "cell_type": "markdown",
857 | "metadata": {},
858 | "source": [
859 | "#### Задание\n",
860 | "\n",
861 | "Измените код выше так, чтобы учитывались:\n",
862 | " 1. Однородные члены предложения \n",
863 | " * (парк, площадка), (Германия, Щвейцария)\n",
864 | " 2. Сложные сказуемые \n",
865 | " * (начнет продавать), (запретил провозить)\n",
866 | " 3. Непрямые объекты\n",
867 | " * (едет, Польшу), (спел, скандале)"
868 | ]
869 | },
870 | {
871 | "cell_type": "code",
872 | "execution_count": null,
873 | "metadata": {},
874 | "outputs": [],
875 | "source": []
876 | },
877 | {
878 | "cell_type": "markdown",
879 | "metadata": {},
880 | "source": [
881 | "# Sentiment Analysis with Recursive Neural Network\n",
882 | "\n",
883 | "* [источник туториала](https://medium.com/@keisukeumezawa/chainer-tutorial-sentiment-analysis-with-recursive-neural-network-180ddde892a2)\n",
884 | "* [статья](https://nlp.stanford.edu/~socherr/EMNLP2013_RNTN.pdf); архитектура описана в 4 секции\n",
885 | "* [демо с кликабельными картинками](http://nlp.stanford.edu:8080/sentiment/rntnDemo.html)"
886 | ]
887 | },
888 | {
889 | "cell_type": "markdown",
890 | "metadata": {},
891 | "source": [
892 | "До сих пор мы смотрели на парсинг зависимостей, но для анализа тональности в этой части используется другой подход, *парсинг составляющих*, или *constituency parsing*. \n",
893 | " "
894 | ]
895 | },
896 | {
897 | "cell_type": "markdown",
898 | "metadata": {},
899 | "source": [
900 | "### Идея\n",
901 | "\n",
902 | "Сентимент предложения складывается из сентимента его составляющих, а тех -- в свою очередь, из их составляющих.\n",
903 | "\n",
904 | "\n",
905 | "\n",
906 | "(в датасете 5 классов тональности: --, -, 0, +, ++)"
907 | ]
908 | },
909 | {
910 | "attachments": {},
911 | "cell_type": "markdown",
912 | "metadata": {},
913 | "source": [
914 | "### Recursive Neural Network\n",
915 | "\n",
916 | "Это нейросети, которые работают с данными переменной длины, используя иерархические структуры (деревья).\n",
917 | "Скрытое состояние i-той вершины дерева вычисляются из скрытых состояний её левого и правого ребёнка:\n",
918 | "\n",
919 | "\n",
920 | "\n",
921 | "\n",
922 | "Векторные представления фраз (узлов дерева) подаются на вход слою-классификатору тональности и слою softmax (в обучающем датасете все составляющие размечены по тональности)."
923 | ]
924 | },
925 | {
926 | "cell_type": "markdown",
927 | "metadata": {},
928 | "source": [
929 | "А теперь давайте посмотрим на код: [jupyter notebook](https://chainer-colab-notebook.readthedocs.io/en/latest/notebook/official_example/sentiment.html), [репозиторий](https://github.com/chainer/chainer/tree/master/examples/sentiment)."
930 | ]
931 | }
932 | ],
933 | "metadata": {
934 | "kernelspec": {
935 | "display_name": "Python 3",
936 | "language": "python",
937 | "name": "python3"
938 | },
939 | "language_info": {
940 | "codemirror_mode": {
941 | "name": "ipython",
942 | "version": 3
943 | },
944 | "file_extension": ".py",
945 | "mimetype": "text/x-python",
946 | "name": "python",
947 | "nbconvert_exporter": "python",
948 | "pygments_lexer": "ipython3",
949 | "version": "3.5.2"
950 | }
951 | },
952 | "nbformat": 4,
953 | "nbformat_minor": 2
954 | }
955 |
--------------------------------------------------------------------------------
/seminars/8/sentiment_recursiveNN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PragmaticsLab/NLP-course-FinTech/5c1bfbaec23264753f79e08e17fde2a724b30356/seminars/8/sentiment_recursiveNN.png
--------------------------------------------------------------------------------