VerVelVel commited on
Commit
169057e
1 Parent(s): 9f7ee75

logreg and toxic bert

Browse files
Hello.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+
4
+ st.set_page_config(
5
+ page_title="Hello",
6
+ page_icon="👋",
7
+ )
8
+
9
+ st.write("# Добро пожаловать на страничку нашего проекта! 👋")
10
+
11
+ st.sidebar.success("Выберите интересующую вас задачу.")
12
+
13
+ st.markdown(
14
+ """
15
+
16
+ **👈 Выберите интересующую вас задачу и наши модели постараются вам помочь!**
17
+ ### Что можно найти в этом сервисе?
18
+ - Страницу, позволяющую выполнить классификацию отзыва на поликлиники (при помощи трех различных моделей)
19
+ - Страницу, позволяющую выполнить оценку степени токсичности пользовательского сообщения с помощью модели rubert-tiny-toxicity
20
+ - Страницу, позволяющую выполнить генерацию текста GPT-моделью по пользовательскому prompt
21
+ - Страницу с информацией о:
22
+ - - процессе обучения модели: кривые обучения и метрик
23
+ - - времени обучения
24
+ - - значениях метрик
25
+
26
+ ### Над проектом трудились:
27
+ - [Даша](https://github.com/Dasha0203)
28
+ - [Вера](https://github.com/VerVelVel)
29
+ """
30
+ )
images/pipeline_logreg.png ADDED
images/toxity_metrics.png ADDED
models/model1/logistic_regression_pipeline.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e522e0db3ea799a291336149ab421d2ec56a6ea03e402bd438bec16b92a49dfb
3
+ size 5705593
models/model1/model_weights.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:da7fd2151d6a5446fc178462ff93ee61c24f98cb0aa41343e2e8c36802e2170b
3
+ size 47712485
models/sds ADDED
File without changes
notebooks/first_ml.ipynb ADDED
@@ -0,0 +1,1539 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# TF-IDF"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "code",
12
+ "execution_count": 50,
13
+ "metadata": {},
14
+ "outputs": [],
15
+ "source": [
16
+ "import numpy as np\n",
17
+ "import pandas as pd\n",
18
+ "import re\n",
19
+ "import string\n",
20
+ "from collections import defaultdict\n",
21
+ "from sklearn import metrics\n",
22
+ "from time import time\n",
23
+ "from nltk.corpus import stopwords\n",
24
+ "from nltk.stem import WordNetLemmatizer\n",
25
+ "from nltk.tokenize import RegexpTokenizer\n",
26
+ "from sklearn.feature_extraction.text import TfidfVectorizer\n",
27
+ "from sklearn.cluster import KMeans\n",
28
+ "from sklearn.datasets import fetch_20newsgroups\n",
29
+ "from sklearn.decomposition import TruncatedSVD\n",
30
+ "from sklearn.pipeline import make_pipeline\n",
31
+ "from sklearn.preprocessing import Normalizer\n",
32
+ "import pymorphy2\n",
33
+ "from sklearn.model_selection import train_test_split\n",
34
+ "from sklearn.linear_model import LogisticRegression\n",
35
+ "from sklearn.metrics import classification_report, accuracy_score, f1_score"
36
+ ]
37
+ },
38
+ {
39
+ "cell_type": "markdown",
40
+ "metadata": {},
41
+ "source": [
42
+ "## Загрузка данных"
43
+ ]
44
+ },
45
+ {
46
+ "cell_type": "code",
47
+ "execution_count": 7,
48
+ "metadata": {},
49
+ "outputs": [],
50
+ "source": [
51
+ "df = pd.read_json('data/healthcare_facilities_reviews.jsonl', lines=True)"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "code",
56
+ "execution_count": 8,
57
+ "metadata": {},
58
+ "outputs": [
59
+ {
60
+ "data": {
61
+ "text/html": [
62
+ "<div>\n",
63
+ "<style scoped>\n",
64
+ " .dataframe tbody tr th:only-of-type {\n",
65
+ " vertical-align: middle;\n",
66
+ " }\n",
67
+ "\n",
68
+ " .dataframe tbody tr th {\n",
69
+ " vertical-align: top;\n",
70
+ " }\n",
71
+ "\n",
72
+ " .dataframe thead th {\n",
73
+ " text-align: right;\n",
74
+ " }\n",
75
+ "</style>\n",
76
+ "<table border=\"1\" class=\"dataframe\">\n",
77
+ " <thead>\n",
78
+ " <tr style=\"text-align: right;\">\n",
79
+ " <th></th>\n",
80
+ " <th>review_id</th>\n",
81
+ " <th>category</th>\n",
82
+ " <th>title</th>\n",
83
+ " <th>content</th>\n",
84
+ " <th>sentiment</th>\n",
85
+ " <th>source_url</th>\n",
86
+ " </tr>\n",
87
+ " </thead>\n",
88
+ " <tbody>\n",
89
+ " <tr>\n",
90
+ " <th>0</th>\n",
91
+ " <td>0</td>\n",
92
+ " <td>Поликлиники стоматологические</td>\n",
93
+ " <td>Классный мастер</td>\n",
94
+ " <td>Огромное спасибо за чудесное удаление двух зуб...</td>\n",
95
+ " <td>positive</td>\n",
96
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=2727539</td>\n",
97
+ " </tr>\n",
98
+ " <tr>\n",
99
+ " <th>1</th>\n",
100
+ " <td>1</td>\n",
101
+ " <td>Поликлиники стоматологические</td>\n",
102
+ " <td>Замечательный врач</td>\n",
103
+ " <td>Хочу выразить особую благодарность замечательн...</td>\n",
104
+ " <td>positive</td>\n",
105
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=2302877</td>\n",
106
+ " </tr>\n",
107
+ " <tr>\n",
108
+ " <th>2</th>\n",
109
+ " <td>2</td>\n",
110
+ " <td>Поликлиники стоматологические</td>\n",
111
+ " <td>Благодарность работникам рентгена</td>\n",
112
+ " <td>Добрый вечер! Хотелось бы поблагодарить сотруд...</td>\n",
113
+ " <td>positive</td>\n",
114
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=2815031</td>\n",
115
+ " </tr>\n",
116
+ " <tr>\n",
117
+ " <th>3</th>\n",
118
+ " <td>3</td>\n",
119
+ " <td>Поликлиники стоматологические</td>\n",
120
+ " <td>Доктор Рабинович</td>\n",
121
+ " <td>Женщины советского образца в регистратуре не и...</td>\n",
122
+ " <td>negative</td>\n",
123
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=3443161</td>\n",
124
+ " </tr>\n",
125
+ " <tr>\n",
126
+ " <th>4</th>\n",
127
+ " <td>4</td>\n",
128
+ " <td>Поликлиники стоматологические</td>\n",
129
+ " <td>Есть кому сказать спасибо</td>\n",
130
+ " <td>У меня с детства очень плохие зубы (тонкая и х...</td>\n",
131
+ " <td>positive</td>\n",
132
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=2592430</td>\n",
133
+ " </tr>\n",
134
+ " <tr>\n",
135
+ " <th>...</th>\n",
136
+ " <td>...</td>\n",
137
+ " <td>...</td>\n",
138
+ " <td>...</td>\n",
139
+ " <td>...</td>\n",
140
+ " <td>...</td>\n",
141
+ " <td>...</td>\n",
142
+ " </tr>\n",
143
+ " <tr>\n",
144
+ " <th>70592</th>\n",
145
+ " <td>70592</td>\n",
146
+ " <td>Водительские комиссии</td>\n",
147
+ " <td>Хуже районной поликлиники</td>\n",
148
+ " <td>Заведение ужасное. Врачи делят 1 кабинет на 2х...</td>\n",
149
+ " <td>negative</td>\n",
150
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=273326</td>\n",
151
+ " </tr>\n",
152
+ " <tr>\n",
153
+ " <th>70593</th>\n",
154
+ " <td>70593</td>\n",
155
+ " <td>Водительские комиссии</td>\n",
156
+ " <td>Справки</td>\n",
157
+ " <td>Люди, не обращайтесь в эту фирму! Муж проходил...</td>\n",
158
+ " <td>negative</td>\n",
159
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=3401583</td>\n",
160
+ " </tr>\n",
161
+ " <tr>\n",
162
+ " <th>70594</th>\n",
163
+ " <td>70594</td>\n",
164
+ " <td>Водительские комиссии</td>\n",
165
+ " <td>Мед-Альфа - это наше будущее</td>\n",
166
+ " <td>Дорогие посетители медицинского центра ООО \"Ме...</td>\n",
167
+ " <td>positive</td>\n",
168
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=326078</td>\n",
169
+ " </tr>\n",
170
+ " <tr>\n",
171
+ " <th>70595</th>\n",
172
+ " <td>70595</td>\n",
173
+ " <td>Водительские комиссии</td>\n",
174
+ " <td>Хамское поведение</td>\n",
175
+ " <td>В регистратуре сидит хамка, такое отношение и ...</td>\n",
176
+ " <td>negative</td>\n",
177
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=3171911</td>\n",
178
+ " </tr>\n",
179
+ " <tr>\n",
180
+ " <th>70596</th>\n",
181
+ " <td>70596</td>\n",
182
+ " <td>Водительские комиссии</td>\n",
183
+ " <td>Только хорошие впечатления</td>\n",
184
+ " <td>Хочу поблагодарить весь персонал \"МедАльфаПроф...</td>\n",
185
+ " <td>positive</td>\n",
186
+ " <td>http://www.spr.ru/forum_vyvod.php?id_tema=3391562</td>\n",
187
+ " </tr>\n",
188
+ " </tbody>\n",
189
+ "</table>\n",
190
+ "<p>70597 rows × 6 columns</p>\n",
191
+ "</div>"
192
+ ],
193
+ "text/plain": [
194
+ " review_id category \\\n",
195
+ "0 0 Поликлиники стоматологические \n",
196
+ "1 1 Поликлиники стоматологические \n",
197
+ "2 2 Поликлиники стоматологические \n",
198
+ "3 3 Поликлиники стоматологические \n",
199
+ "4 4 Поликлиники стоматологические \n",
200
+ "... ... ... \n",
201
+ "70592 70592 Водительские комиссии \n",
202
+ "70593 70593 Водительские комиссии \n",
203
+ "70594 70594 Водительские комиссии \n",
204
+ "70595 70595 Водительские комиссии \n",
205
+ "70596 70596 Водительские комиссии \n",
206
+ "\n",
207
+ " title \\\n",
208
+ "0 Классный мастер \n",
209
+ "1 Замечательный врач \n",
210
+ "2 Благодарность работникам рентгена \n",
211
+ "3 Доктор Рабинович \n",
212
+ "4 Есть кому сказать спасибо \n",
213
+ "... ... \n",
214
+ "70592 Хуже районной поликлиники \n",
215
+ "70593 Справки \n",
216
+ "70594 Мед-Альфа - это наше будущее \n",
217
+ "70595 Хамское поведение \n",
218
+ "70596 Только хорошие впечатления \n",
219
+ "\n",
220
+ " content sentiment \\\n",
221
+ "0 Огромное спасибо за чудесное удаление двух зуб... positive \n",
222
+ "1 Хочу выразить особую благодарность замечательн... positive \n",
223
+ "2 Добрый вечер! Хотелось бы поблагодарить сотруд... positive \n",
224
+ "3 Женщины советского об��азца в регистратуре не и... negative \n",
225
+ "4 У меня с детства очень плохие зубы (тонкая и х... positive \n",
226
+ "... ... ... \n",
227
+ "70592 Заведение ужасное. Врачи делят 1 кабинет на 2х... negative \n",
228
+ "70593 Люди, не обращайтесь в эту фирму! Муж проходил... negative \n",
229
+ "70594 Дорогие посетители медицинского центра ООО \"Ме... positive \n",
230
+ "70595 В регистратуре сидит хамка, такое отношение и ... negative \n",
231
+ "70596 Хочу поблагодарить весь персонал \"МедАльфаПроф... positive \n",
232
+ "\n",
233
+ " source_url \n",
234
+ "0 http://www.spr.ru/forum_vyvod.php?id_tema=2727539 \n",
235
+ "1 http://www.spr.ru/forum_vyvod.php?id_tema=2302877 \n",
236
+ "2 http://www.spr.ru/forum_vyvod.php?id_tema=2815031 \n",
237
+ "3 http://www.spr.ru/forum_vyvod.php?id_tema=3443161 \n",
238
+ "4 http://www.spr.ru/forum_vyvod.php?id_tema=2592430 \n",
239
+ "... ... \n",
240
+ "70592 http://www.spr.ru/forum_vyvod.php?id_tema=273326 \n",
241
+ "70593 http://www.spr.ru/forum_vyvod.php?id_tema=3401583 \n",
242
+ "70594 http://www.spr.ru/forum_vyvod.php?id_tema=326078 \n",
243
+ "70595 http://www.spr.ru/forum_vyvod.php?id_tema=3171911 \n",
244
+ "70596 http://www.spr.ru/forum_vyvod.php?id_tema=3391562 \n",
245
+ "\n",
246
+ "[70597 rows x 6 columns]"
247
+ ]
248
+ },
249
+ "execution_count": 8,
250
+ "metadata": {},
251
+ "output_type": "execute_result"
252
+ }
253
+ ],
254
+ "source": [
255
+ "df"
256
+ ]
257
+ },
258
+ {
259
+ "cell_type": "code",
260
+ "execution_count": 9,
261
+ "metadata": {},
262
+ "outputs": [],
263
+ "source": [
264
+ "df = df[['sentiment', 'content']]"
265
+ ]
266
+ },
267
+ {
268
+ "cell_type": "code",
269
+ "execution_count": 10,
270
+ "metadata": {},
271
+ "outputs": [
272
+ {
273
+ "data": {
274
+ "text/html": [
275
+ "<div>\n",
276
+ "<style scoped>\n",
277
+ " .dataframe tbody tr th:only-of-type {\n",
278
+ " vertical-align: middle;\n",
279
+ " }\n",
280
+ "\n",
281
+ " .dataframe tbody tr th {\n",
282
+ " vertical-align: top;\n",
283
+ " }\n",
284
+ "\n",
285
+ " .dataframe thead th {\n",
286
+ " text-align: right;\n",
287
+ " }\n",
288
+ "</style>\n",
289
+ "<table border=\"1\" class=\"dataframe\">\n",
290
+ " <thead>\n",
291
+ " <tr style=\"text-align: right;\">\n",
292
+ " <th></th>\n",
293
+ " <th>sentiment</th>\n",
294
+ " <th>content</th>\n",
295
+ " </tr>\n",
296
+ " </thead>\n",
297
+ " <tbody>\n",
298
+ " <tr>\n",
299
+ " <th>0</th>\n",
300
+ " <td>positive</td>\n",
301
+ " <td>Огромное спасибо за чудесное удаление двух зуб...</td>\n",
302
+ " </tr>\n",
303
+ " <tr>\n",
304
+ " <th>1</th>\n",
305
+ " <td>positive</td>\n",
306
+ " <td>Хочу выразить особую благодарность замечательн...</td>\n",
307
+ " </tr>\n",
308
+ " <tr>\n",
309
+ " <th>2</th>\n",
310
+ " <td>positive</td>\n",
311
+ " <td>Добрый вечер! Хотелось бы поблагодарить сотруд...</td>\n",
312
+ " </tr>\n",
313
+ " <tr>\n",
314
+ " <th>3</th>\n",
315
+ " <td>negative</td>\n",
316
+ " <td>Женщины советского образца в регистратуре не и...</td>\n",
317
+ " </tr>\n",
318
+ " <tr>\n",
319
+ " <th>4</th>\n",
320
+ " <td>positive</td>\n",
321
+ " <td>У меня с детства очень плохие зубы (тонкая и х...</td>\n",
322
+ " </tr>\n",
323
+ " <tr>\n",
324
+ " <th>...</th>\n",
325
+ " <td>...</td>\n",
326
+ " <td>...</td>\n",
327
+ " </tr>\n",
328
+ " <tr>\n",
329
+ " <th>70592</th>\n",
330
+ " <td>negative</td>\n",
331
+ " <td>Заведение ужасное. Врачи делят 1 кабинет на 2х...</td>\n",
332
+ " </tr>\n",
333
+ " <tr>\n",
334
+ " <th>70593</th>\n",
335
+ " <td>negative</td>\n",
336
+ " <td>Люди, не обращайтесь в эту фирму! Муж проходил...</td>\n",
337
+ " </tr>\n",
338
+ " <tr>\n",
339
+ " <th>70594</th>\n",
340
+ " <td>positive</td>\n",
341
+ " <td>Дорогие посетители медицинского центра ООО \"Ме...</td>\n",
342
+ " </tr>\n",
343
+ " <tr>\n",
344
+ " <th>70595</th>\n",
345
+ " <td>negative</td>\n",
346
+ " <td>В регистратуре сидит ��амка, такое отношение и ...</td>\n",
347
+ " </tr>\n",
348
+ " <tr>\n",
349
+ " <th>70596</th>\n",
350
+ " <td>positive</td>\n",
351
+ " <td>Хочу поблагодарить весь персонал \"МедАльфаПроф...</td>\n",
352
+ " </tr>\n",
353
+ " </tbody>\n",
354
+ "</table>\n",
355
+ "<p>70597 rows × 2 columns</p>\n",
356
+ "</div>"
357
+ ],
358
+ "text/plain": [
359
+ " sentiment content\n",
360
+ "0 positive Огромное спасибо за чудесное удаление двух зуб...\n",
361
+ "1 positive Хочу выразить особую благодарность замечательн...\n",
362
+ "2 positive Добрый вечер! Хотелось бы поблагодарить сотруд...\n",
363
+ "3 negative Женщины советского образца в регистратуре не и...\n",
364
+ "4 positive У меня с детства очень плохие зубы (тонкая и х...\n",
365
+ "... ... ...\n",
366
+ "70592 negative Заведение ужасное. Врачи делят 1 кабинет на 2х...\n",
367
+ "70593 negative Люди, не обращайтесь в эту фирму! Муж проходил...\n",
368
+ "70594 positive Дорогие посетители медицинского центра ООО \"Ме...\n",
369
+ "70595 negative В регистратуре сидит хамка, такое отношение и ...\n",
370
+ "70596 positive Хочу поблагодарить весь персонал \"МедАльфаПроф...\n",
371
+ "\n",
372
+ "[70597 rows x 2 columns]"
373
+ ]
374
+ },
375
+ "execution_count": 10,
376
+ "metadata": {},
377
+ "output_type": "execute_result"
378
+ }
379
+ ],
380
+ "source": [
381
+ "df"
382
+ ]
383
+ },
384
+ {
385
+ "cell_type": "code",
386
+ "execution_count": 12,
387
+ "metadata": {},
388
+ "outputs": [
389
+ {
390
+ "data": {
391
+ "text/plain": [
392
+ "'Добрый вечер! Хотелось бы поблагодарить сотрудников рентгена! Протезируюсь, отношусь к поликлинике № 189. Там меня отфутболили! Подходила к Кочину, зам. гл. врачу, заведующей просто сделать 3 снимка (пол-ка рядом с домом)- мне грубо отказали! А сотрудник рентгена просто сидела кроссворд разгадывала! Они видите ли, не принимают с протезирования! Сказали, где протезируетесь, там и делайте, а я говорю, мне у Вас удобно. Побоялись они! Первый раз попала к молодой девушке, она меня выслушала и сделала 1 снимок, а потом записала на другие дни, мне это удобно. Конечно, народу полно было! Бедные сотрудники. Все, кто читает отзыв (особенно жители Люблино 189 пол-ки), давайте жаловаться в департамент! Спасибо еще раз, за рентген (слышала в очереди, что народу у Вас было много и вы уже перебрали с нормой). Спасибо.'"
393
+ ]
394
+ },
395
+ "execution_count": 12,
396
+ "metadata": {},
397
+ "output_type": "execute_result"
398
+ }
399
+ ],
400
+ "source": [
401
+ "df['content'][2]"
402
+ ]
403
+ },
404
+ {
405
+ "cell_type": "markdown",
406
+ "metadata": {},
407
+ "source": [
408
+ "## Очистка текста"
409
+ ]
410
+ },
411
+ {
412
+ "cell_type": "code",
413
+ "execution_count": 25,
414
+ "metadata": {},
415
+ "outputs": [],
416
+ "source": [
417
+ "morph = pymorphy2.MorphAnalyzer()\n",
418
+ "russian_stopwords = stopwords.words(\"russian\")"
419
+ ]
420
+ },
421
+ {
422
+ "cell_type": "code",
423
+ "execution_count": 26,
424
+ "metadata": {},
425
+ "outputs": [
426
+ {
427
+ "name": "stderr",
428
+ "output_type": "stream",
429
+ "text": [
430
+ "/tmp/ipykernel_75887/650983554.py:12: SettingWithCopyWarning: \n",
431
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
432
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
433
+ "\n",
434
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
435
+ " df['cleaned_text'] = df['content'].apply(clean_text)\n"
436
+ ]
437
+ }
438
+ ],
439
+ "source": [
440
+ "def clean_text(text):\n",
441
+ " # Удаление всего, что не является буквами или знаками препинания\n",
442
+ " clean_pattern = re.compile(r'[^a-zA-Zа-яА-ЯёЁ0-9.,!?;:\\s]')\n",
443
+ " text = clean_pattern.sub('', text)\n",
444
+ " url_pattern = re.compile(r'http\\S+|www\\S+|https\\S+')\n",
445
+ " text = url_pattern.sub(r'', text)\n",
446
+ " text = text.translate(str.maketrans('', '', string.punctuation))\n",
447
+ " text = text.lower()\n",
448
+ " lemmatized_text = ' '.join([morph.parse(word)[0].normal_form for word in text.split() if word not in russian_stopwords])\n",
449
+ " return lemmatized_text\n",
450
+ "\n",
451
+ "df['cleaned_text'] = df['content'].apply(clean_text)"
452
+ ]
453
+ },
454
+ {
455
+ "cell_type": "code",
456
+ "execution_count": 28,
457
+ "metadata": {},
458
+ "outputs": [
459
+ {
460
+ "data": {
461
+ "text/html": [
462
+ "<div>\n",
463
+ "<style scoped>\n",
464
+ " .dataframe tbody tr th:only-of-type {\n",
465
+ " vertical-align: middle;\n",
466
+ " }\n",
467
+ "\n",
468
+ " .dataframe tbody tr th {\n",
469
+ " vertical-align: top;\n",
470
+ " }\n",
471
+ "\n",
472
+ " .dataframe thead th {\n",
473
+ " text-align: right;\n",
474
+ " }\n",
475
+ "</style>\n",
476
+ "<table border=\"1\" class=\"dataframe\">\n",
477
+ " <thead>\n",
478
+ " <tr style=\"text-align: right;\">\n",
479
+ " <th></th>\n",
480
+ " <th>sentiment</th>\n",
481
+ " <th>content</th>\n",
482
+ " <th>cleaned_text</th>\n",
483
+ " </tr>\n",
484
+ " </thead>\n",
485
+ " <tbody>\n",
486
+ " <tr>\n",
487
+ " <th>0</th>\n",
488
+ " <td>positive</td>\n",
489
+ " <td>Огромное спасибо за чудесное удаление двух зуб...</td>\n",
490
+ " <td>огромный спасибо чудесный удаление два зуб муд...</td>\n",
491
+ " </tr>\n",
492
+ " <tr>\n",
493
+ " <th>1</th>\n",
494
+ " <td>positive</td>\n",
495
+ " <td>Хочу выразить особую благодарность замечательн...</td>\n",
496
+ " <td>хотеть выразить особый благодарность замечател...</td>\n",
497
+ " </tr>\n",
498
+ " <tr>\n",
499
+ " <th>2</th>\n",
500
+ " <td>positive</td>\n",
501
+ " <td>Добрый вечер! Хотелось бы поблагодарить сотруд...</td>\n",
502
+ " <td>добрый вечер хотеться поблагодарить сотрудник ...</td>\n",
503
+ " </tr>\n",
504
+ " <tr>\n",
505
+ " <th>3</th>\n",
506
+ " <td>negative</td>\n",
507
+ " <td>Женщины советского образца в регистратуре не и...</td>\n",
508
+ " <td>женщина советский образец регистратура иметь п...</td>\n",
509
+ " </tr>\n",
510
+ " <tr>\n",
511
+ " <th>4</th>\n",
512
+ " <td>positive</td>\n",
513
+ " <td>У меня с детства очень плохие зубы (тонкая и х...</td>\n",
514
+ " <td>детство очень плохой зуб тонкий хрупкий эмаль ...</td>\n",
515
+ " </tr>\n",
516
+ " <tr>\n",
517
+ " <th>...</th>\n",
518
+ " <td>...</td>\n",
519
+ " <td>...</td>\n",
520
+ " <td>...</td>\n",
521
+ " </tr>\n",
522
+ " <tr>\n",
523
+ " <th>70592</th>\n",
524
+ " <td>negative</td>\n",
525
+ " <td>Заведение ужасное. Врачи делят 1 кабинет на 2х...</td>\n",
526
+ " <td>заведение ужасный врач делить 1 кабинет 2х спе...</td>\n",
527
+ " </tr>\n",
528
+ " <tr>\n",
529
+ " <th>70593</th>\n",
530
+ " <td>negative</td>\n",
531
+ " <td>Люди, не обращайтесь в эту фирму! Муж проходил...</td>\n",
532
+ " <td>человек обращаться фирма муж проходить анализ ...</td>\n",
533
+ " </tr>\n",
534
+ " <tr>\n",
535
+ " <th>70594</th>\n",
536
+ " <td>positive</td>\n",
537
+ " <td>Дорогие посетители медицинского центра ООО \"Ме...</td>\n",
538
+ " <td>дорогой посетитель медицинский центр ооо медал...</td>\n",
539
+ " </tr>\n",
540
+ " <tr>\n",
541
+ " <th>70595</th>\n",
542
+ " <td>negative</td>\n",
543
+ " <td>В регистратуре сидит хамка, такое отношение и ...</td>\n",
544
+ " <td>регистратура сидеть хамка такой отношение мане...</td>\n",
545
+ " </tr>\n",
546
+ " <tr>\n",
547
+ " <th>70596</th>\n",
548
+ " <td>positive</td>\n",
549
+ " <td>Хочу поблагодарить весь персонал \"МедАльфаПроф...</td>\n",
550
+ " <td>хотеть поблагодарить весь персонал медальфапро...</td>\n",
551
+ " </tr>\n",
552
+ " </tbody>\n",
553
+ "</table>\n",
554
+ "<p>70597 rows × 3 columns</p>\n",
555
+ "</div>"
556
+ ],
557
+ "text/plain": [
558
+ " sentiment content \\\n",
559
+ "0 positive Огромное спасибо за чудесное удаление двух зуб... \n",
560
+ "1 positive Хочу выразить особую благодарность замечательн... \n",
561
+ "2 positive Добрый вечер! Хотелось бы поблагодарить сотруд... \n",
562
+ "3 negative Женщины советского образца в регистратуре не и... \n",
563
+ "4 positive У меня с детства очень плохие зубы (тонкая и х... \n",
564
+ "... ... ... \n",
565
+ "70592 negative Заведение ужасное. Врачи делят 1 кабинет на 2х... \n",
566
+ "70593 negative Люди, не обращайтесь в эту фирму! Муж проходил... \n",
567
+ "70594 positive Дорогие посетители медицинского центра ООО \"Ме... \n",
568
+ "70595 negative В регистратуре сидит хамка, такое отношение и ... \n",
569
+ "70596 positive Хочу поблагодарить весь персонал \"МедАльфаПроф... \n",
570
+ "\n",
571
+ " cleaned_text \n",
572
+ "0 огромный спасибо чудесный удаление два зуб муд... \n",
573
+ "1 хотеть выразить особый благодарность замечател... \n",
574
+ "2 добрый вечер хотеться поблагодарить сотрудник ... \n",
575
+ "3 женщина советский образец регистратура иметь п... \n",
576
+ "4 детство очень плохой зуб тонкий хрупкий эмаль ... \n",
577
+ "... ... \n",
578
+ "70592 заведение ужасный врач делить 1 кабинет 2х спе... \n",
579
+ "70593 человек обращаться фирма муж проходить анализ ... \n",
580
+ "70594 дорогой посетитель медицинский центр ооо медал... \n",
581
+ "70595 регистратура сидеть хамка такой отношение мане... \n",
582
+ "70596 хотеть поблагодарить весь персонал медальфапро... \n",
583
+ "\n",
584
+ "[70597 rows x 3 columns]"
585
+ ]
586
+ },
587
+ "execution_count": 28,
588
+ "metadata": {},
589
+ "output_type": "execute_result"
590
+ }
591
+ ],
592
+ "source": [
593
+ "df"
594
+ ]
595
+ },
596
+ {
597
+ "cell_type": "code",
598
+ "execution_count": 29,
599
+ "metadata": {},
600
+ "outputs": [
601
+ {
602
+ "data": {
603
+ "text/plain": [
604
+ "'добрый вечер хотеться поблагодарить сотрудник рентген протезироваться относиться поликлиника 189 отфутболить подходить кочин зам гл врач заведовать просто сделать 3 снимок полка рядом дом грубо отказать сотрудник рентген просто сидеть кроссворд разгадывать видеть принимать протезирование сказать протезироваться делать говорить удобно побояться первый попасть молодой девушка выслушать сделать 1 снимка записать другой день это удобно народ полно бедный сотрудник читать отзыв особенно житель люблино 189 полка давать жаловаться департамент спасибо рентген слышать очередь народ перебрать норма спасибо'"
605
+ ]
606
+ },
607
+ "execution_count": 29,
608
+ "metadata": {},
609
+ "output_type": "execute_result"
610
+ }
611
+ ],
612
+ "source": [
613
+ "df['cleaned_text'][2]"
614
+ ]
615
+ },
616
+ {
617
+ "cell_type": "code",
618
+ "execution_count": 34,
619
+ "metadata": {},
620
+ "outputs": [
621
+ {
622
+ "name": "stderr",
623
+ "output_type": "stream",
624
+ "text": [
625
+ "/tmp/ipykernel_75887/3526150694.py:1: SettingWithCopyWarning: \n",
626
+ "A value is trying to be set on a copy of a slice from a DataFrame.\n",
627
+ "Try using .loc[row_indexer,col_indexer] = value instead\n",
628
+ "\n",
629
+ "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
630
+ " df['sentiment'] = df['sentiment'].apply(lambda x: 1 if x == 'negative' else 0)\n"
631
+ ]
632
+ }
633
+ ],
634
+ "source": [
635
+ "df['sentiment'] = df['sentiment'].apply(lambda x: 1 if x == 'negative' else 0)"
636
+ ]
637
+ },
638
+ {
639
+ "cell_type": "code",
640
+ "execution_count": 35,
641
+ "metadata": {},
642
+ "outputs": [
643
+ {
644
+ "data": {
645
+ "text/html": [
646
+ "<div>\n",
647
+ "<style scoped>\n",
648
+ " .dataframe tbody tr th:only-of-type {\n",
649
+ " vertical-align: middle;\n",
650
+ " }\n",
651
+ "\n",
652
+ " .dataframe tbody tr th {\n",
653
+ " vertical-align: top;\n",
654
+ " }\n",
655
+ "\n",
656
+ " .dataframe thead th {\n",
657
+ " text-align: right;\n",
658
+ " }\n",
659
+ "</style>\n",
660
+ "<table border=\"1\" class=\"dataframe\">\n",
661
+ " <thead>\n",
662
+ " <tr style=\"text-align: right;\">\n",
663
+ " <th></th>\n",
664
+ " <th>sentiment</th>\n",
665
+ " <th>content</th>\n",
666
+ " <th>cleaned_text</th>\n",
667
+ " </tr>\n",
668
+ " </thead>\n",
669
+ " <tbody>\n",
670
+ " <tr>\n",
671
+ " <th>0</th>\n",
672
+ " <td>0</td>\n",
673
+ " <td>Огромное спасибо за чудесное удаление двух зуб...</td>\n",
674
+ " <td>огромный спасибо чудесный удаление два зуб муд...</td>\n",
675
+ " </tr>\n",
676
+ " <tr>\n",
677
+ " <th>1</th>\n",
678
+ " <td>0</td>\n",
679
+ " <td>Хочу выразить особую благодарность замечательн...</td>\n",
680
+ " <td>хотеть выразить особый благодарность замечател...</td>\n",
681
+ " </tr>\n",
682
+ " <tr>\n",
683
+ " <th>2</th>\n",
684
+ " <td>0</td>\n",
685
+ " <td>Добрый вечер! Хотелось бы поблагодарить сотруд...</td>\n",
686
+ " <td>добрый вечер хотеться поблагодарить сотрудник ...</td>\n",
687
+ " </tr>\n",
688
+ " <tr>\n",
689
+ " <th>3</th>\n",
690
+ " <td>1</td>\n",
691
+ " <td>Женщины советского образца в регистратуре не и...</td>\n",
692
+ " <td>женщина советский образец регистратура иметь п...</td>\n",
693
+ " </tr>\n",
694
+ " <tr>\n",
695
+ " <th>4</th>\n",
696
+ " <td>0</td>\n",
697
+ " <td>У меня с детства очень плохие зубы (тонкая и х...</td>\n",
698
+ " <td>детство очень плохой зуб тонкий хрупкий эмаль ...</td>\n",
699
+ " </tr>\n",
700
+ " <tr>\n",
701
+ " <th>...</th>\n",
702
+ " <td>...</td>\n",
703
+ " <td>...</td>\n",
704
+ " <td>...</td>\n",
705
+ " </tr>\n",
706
+ " <tr>\n",
707
+ " <th>70592</th>\n",
708
+ " <td>1</td>\n",
709
+ " <td>Заведение ужасное. Врачи делят 1 кабинет на 2х...</td>\n",
710
+ " <td>заведение ужасный врач делить 1 кабинет 2х спе...</td>\n",
711
+ " </tr>\n",
712
+ " <tr>\n",
713
+ " <th>70593</th>\n",
714
+ " <td>1</td>\n",
715
+ " <td>Люди, не обращайтесь в эту фирму! Муж проходил...</td>\n",
716
+ " <td>человек обращаться фирма муж проходить анализ ...</td>\n",
717
+ " </tr>\n",
718
+ " <tr>\n",
719
+ " <th>70594</th>\n",
720
+ " <td>0</td>\n",
721
+ " <td>Дорогие посетители медицинского центра ООО \"Ме...</td>\n",
722
+ " <td>дорогой посетитель медицинский центр ооо медал...</td>\n",
723
+ " </tr>\n",
724
+ " <tr>\n",
725
+ " <th>70595</th>\n",
726
+ " <td>1</td>\n",
727
+ " <td>В регистратуре сидит хамка, такое отношение и ...</td>\n",
728
+ " <td>регистратура сидеть хамка такой отношение мане...</td>\n",
729
+ " </tr>\n",
730
+ " <tr>\n",
731
+ " <th>70596</th>\n",
732
+ " <td>0</td>\n",
733
+ " <td>Хочу поблагодарить весь персонал \"МедАльфаПроф...</td>\n",
734
+ " <td>хотеть поблагодарить весь персонал медальфапро...</td>\n",
735
+ " </tr>\n",
736
+ " </tbody>\n",
737
+ "</table>\n",
738
+ "<p>70597 rows × 3 columns</p>\n",
739
+ "</div>"
740
+ ],
741
+ "text/plain": [
742
+ " sentiment content \\\n",
743
+ "0 0 Огромное спасибо за чудесное удаление двух зуб... \n",
744
+ "1 0 Хочу выразить особую благодарность замечательн... \n",
745
+ "2 0 Добрый вечер! Хотелось бы поблагодарить сотруд... \n",
746
+ "3 1 Женщины советского образца в регистратуре не и... \n",
747
+ "4 0 У меня с детства очень плохие зубы (тонкая и х... \n",
748
+ "... ... ... \n",
749
+ "70592 1 Заведение ужасное. Врачи делят 1 кабинет на 2х... \n",
750
+ "70593 1 Люди, не обращайтесь в эту фирму! Муж проходил... \n",
751
+ "70594 0 Дорогие посетители медицинского центра ООО \"Ме... \n",
752
+ "70595 1 В регистратуре сидит хамка, такое отношение и ... \n",
753
+ "70596 0 Хочу поблагодарить весь персонал \"МедАльфаПроф... \n",
754
+ "\n",
755
+ " cleaned_text \n",
756
+ "0 огромный спасибо чудесный удаление два зуб муд... \n",
757
+ "1 хотеть выразить особый благодарность замечател... \n",
758
+ "2 добрый вечер хотеться поблагодарить сотрудник ... \n",
759
+ "3 женщина советский образец регистратура иметь п... \n",
760
+ "4 детство очень плохой зуб тонкий хрупкий эмаль ... \n",
761
+ "... ... \n",
762
+ "70592 заведение ужасный врач делить 1 кабинет 2х спе... \n",
763
+ "70593 человек обращаться фирма муж проходить анализ ... \n",
764
+ "70594 дорогой посетитель медицинский центр ооо медал... \n",
765
+ "70595 регистратура сидеть хамка такой отношение мане... \n",
766
+ "70596 хотеть поблагодарить весь персонал медальфапро... \n",
767
+ "\n",
768
+ "[70597 rows x 3 columns]"
769
+ ]
770
+ },
771
+ "execution_count": 35,
772
+ "metadata": {},
773
+ "output_type": "execute_result"
774
+ }
775
+ ],
776
+ "source": [
777
+ "df"
778
+ ]
779
+ },
780
+ {
781
+ "cell_type": "code",
782
+ "execution_count": 46,
783
+ "metadata": {},
784
+ "outputs": [],
785
+ "source": [
786
+ "X_train, X_test, y_train, y_test = train_test_split(df['cleaned_text'], df['sentiment'], test_size=0.2, random_state=42)"
787
+ ]
788
+ },
789
+ {
790
+ "cell_type": "markdown",
791
+ "metadata": {},
792
+ "source": [
793
+ "## Векторизация и сжатие"
794
+ ]
795
+ },
796
+ {
797
+ "cell_type": "code",
798
+ "execution_count": 47,
799
+ "metadata": {},
800
+ "outputs": [
801
+ {
802
+ "name": "stdout",
803
+ "output_type": "stream",
804
+ "text": [
805
+ "vectorization done in 4.084 s\n",
806
+ "n_samples train: 56477, n_features: 1010\n",
807
+ "n_samples test: 14120, n_features: 1010\n"
808
+ ]
809
+ }
810
+ ],
811
+ "source": [
812
+ "vectorizer = TfidfVectorizer(\n",
813
+ " max_df=0.9,\n",
814
+ " min_df=500,\n",
815
+ " # ngram_range=(1, 2), # Использование униграмм и биграмм\n",
816
+ " # max_features=5000,\n",
817
+ " stop_words=stopwords.words('russian'),\n",
818
+ ")\n",
819
+ "t0 = time()\n",
820
+ "X_train_tfidf = vectorizer.fit_transform(X_train)\n",
821
+ "X_test_tfidf = vectorizer.transform(X_test)\n",
822
+ "\n",
823
+ "print(f\"vectorization done in {time() - t0:.3f} s\")\n",
824
+ "print(f\"n_samples train: {X_train_tfidf.shape[0]}, n_features: {X_train_tfidf.shape[1]}\")\n",
825
+ "print(f\"n_samples test: {X_test_tfidf.shape[0]}, n_features: {X_test_tfidf.shape[1]}\")"
826
+ ]
827
+ },
828
+ {
829
+ "cell_type": "code",
830
+ "execution_count": 48,
831
+ "metadata": {},
832
+ "outputs": [
833
+ {
834
+ "name": "stdout",
835
+ "output_type": "stream",
836
+ "text": [
837
+ "LSA done in 14.485 s\n",
838
+ "Explained variance of the SVD step: 74.3%\n"
839
+ ]
840
+ }
841
+ ],
842
+ "source": [
843
+ "lsa = make_pipeline(TruncatedSVD(n_components=500), Normalizer(copy=False))\n",
844
+ "t0 = time()\n",
845
+ "X_train_lsa = lsa.fit_transform(X_train_tfidf)\n",
846
+ "\n",
847
+ "# Применение обученной модели LSA к тестовым данным\n",
848
+ "X_test_lsa = lsa.transform(X_test_tfidf)\n",
849
+ "explained_variance = lsa[0].explained_variance_ratio_.sum()\n",
850
+ "\n",
851
+ "print(f\"LSA done in {time() - t0:.3f} s\")\n",
852
+ "print(f\"Explained variance of the SVD step: {explained_variance * 100:.1f}%\")"
853
+ ]
854
+ },
855
+ {
856
+ "cell_type": "markdown",
857
+ "metadata": {},
858
+ "source": [
859
+ "## Логистическая регрессия"
860
+ ]
861
+ },
862
+ {
863
+ "cell_type": "code",
864
+ "execution_count": 51,
865
+ "metadata": {},
866
+ "outputs": [
867
+ {
868
+ "name": "stdout",
869
+ "output_type": "stream",
870
+ "text": [
871
+ " precision recall f1-score support\n",
872
+ "\n",
873
+ " 0 0.94 0.94 0.94 8342\n",
874
+ " 1 0.91 0.92 0.91 5778\n",
875
+ "\n",
876
+ " accuracy 0.93 14120\n",
877
+ " macro avg 0.92 0.93 0.93 14120\n",
878
+ "weighted avg 0.93 0.93 0.93 14120\n",
879
+ "\n",
880
+ "Accuracy: 0.9277620396600567\n",
881
+ "F1 score: 0.9120689655172414\n"
882
+ ]
883
+ }
884
+ ],
885
+ "source": [
886
+ "model = LogisticRegression()\n",
887
+ "\n",
888
+ "# Обучение модели\n",
889
+ "model.fit(X_train_lsa, y_train)\n",
890
+ "\n",
891
+ "# Прогнозирование на тестовой выборке\n",
892
+ "y_pred = model.predict(X_test_lsa)\n",
893
+ "\n",
894
+ "# Вывод результатов\n",
895
+ "print(classification_report(y_test, y_pred))\n",
896
+ "print(f'Accuracy: {accuracy_score(y_test, y_pred)}')\n",
897
+ "print(f'F1 score: {f1_score(y_test, y_pred)}')"
898
+ ]
899
+ },
900
+ {
901
+ "cell_type": "markdown",
902
+ "metadata": {},
903
+ "source": [
904
+ "## Создание пайплайна"
905
+ ]
906
+ },
907
+ {
908
+ "cell_type": "code",
909
+ "execution_count": 54,
910
+ "metadata": {},
911
+ "outputs": [
912
+ {
913
+ "name": "stderr",
914
+ "output_type": "stream",
915
+ "text": [
916
+ "[nltk_data] Downloading package stopwords to /home/vera/nltk_data...\n",
917
+ "[nltk_data] Package stopwords is already up-to-date!\n",
918
+ "[nltk_data] Downloading package punkt to /home/vera/nltk_data...\n",
919
+ "[nltk_data] Package punkt is already up-to-date!\n"
920
+ ]
921
+ },
922
+ {
923
+ "data": {
924
+ "text/html": [
925
+ "<style>#sk-container-id-1 {\n",
926
+ " /* Definition of color scheme common for light and dark mode */\n",
927
+ " --sklearn-color-text: black;\n",
928
+ " --sklearn-color-line: gray;\n",
929
+ " /* Definition of color scheme for unfitted estimators */\n",
930
+ " --sklearn-color-unfitted-level-0: #fff5e6;\n",
931
+ " --sklearn-color-unfitted-level-1: #f6e4d2;\n",
932
+ " --sklearn-color-unfitted-level-2: #ffe0b3;\n",
933
+ " --sklearn-color-unfitted-level-3: chocolate;\n",
934
+ " /* Definition of color scheme for fitted estimators */\n",
935
+ " --sklearn-color-fitted-level-0: #f0f8ff;\n",
936
+ " --sklearn-color-fitted-level-1: #d4ebff;\n",
937
+ " --sklearn-color-fitted-level-2: #b3dbfd;\n",
938
+ " --sklearn-color-fitted-level-3: cornflowerblue;\n",
939
+ "\n",
940
+ " /* Specific color for light theme */\n",
941
+ " --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
942
+ " --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
943
+ " --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
944
+ " --sklearn-color-icon: #696969;\n",
945
+ "\n",
946
+ " @media (prefers-color-scheme: dark) {\n",
947
+ " /* Redefinition of color scheme for dark theme */\n",
948
+ " --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
949
+ " --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
950
+ " --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
951
+ " --sklearn-color-icon: #878787;\n",
952
+ " }\n",
953
+ "}\n",
954
+ "\n",
955
+ "#sk-container-id-1 {\n",
956
+ " color: var(--sklearn-color-text);\n",
957
+ "}\n",
958
+ "\n",
959
+ "#sk-container-id-1 pre {\n",
960
+ " padding: 0;\n",
961
+ "}\n",
962
+ "\n",
963
+ "#sk-container-id-1 input.sk-hidden--visually {\n",
964
+ " border: 0;\n",
965
+ " clip: rect(1px 1px 1px 1px);\n",
966
+ " clip: rect(1px, 1px, 1px, 1px);\n",
967
+ " height: 1px;\n",
968
+ " margin: -1px;\n",
969
+ " overflow: hidden;\n",
970
+ " padding: 0;\n",
971
+ " position: absolute;\n",
972
+ " width: 1px;\n",
973
+ "}\n",
974
+ "\n",
975
+ "#sk-container-id-1 div.sk-dashed-wrapped {\n",
976
+ " border: 1px dashed var(--sklearn-color-line);\n",
977
+ " margin: 0 0.4em 0.5em 0.4em;\n",
978
+ " box-sizing: border-box;\n",
979
+ " padding-bottom: 0.4em;\n",
980
+ " background-color: var(--sklearn-color-background);\n",
981
+ "}\n",
982
+ "\n",
983
+ "#sk-container-id-1 div.sk-container {\n",
984
+ " /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
985
+ " but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
986
+ " so we also need the `!important` here to be able to override the\n",
987
+ " default hidden behavior on the sphinx rendered scikit-learn.org.\n",
988
+ " See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
989
+ " display: inline-block !important;\n",
990
+ " position: relative;\n",
991
+ "}\n",
992
+ "\n",
993
+ "#sk-container-id-1 div.sk-text-repr-fallback {\n",
994
+ " display: none;\n",
995
+ "}\n",
996
+ "\n",
997
+ "div.sk-parallel-item,\n",
998
+ "div.sk-serial,\n",
999
+ "div.sk-item {\n",
1000
+ " /* draw centered vertical line to link estimators */\n",
1001
+ " background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
1002
+ " background-size: 2px 100%;\n",
1003
+ " background-repeat: no-repeat;\n",
1004
+ " background-position: center center;\n",
1005
+ "}\n",
1006
+ "\n",
1007
+ "/* Parallel-specific style estimator block */\n",
1008
+ "\n",
1009
+ "#sk-container-id-1 div.sk-parallel-item::after {\n",
1010
+ " content: \"\";\n",
1011
+ " width: 100%;\n",
1012
+ " border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
1013
+ " flex-grow: 1;\n",
1014
+ "}\n",
1015
+ "\n",
1016
+ "#sk-container-id-1 div.sk-parallel {\n",
1017
+ " display: flex;\n",
1018
+ " align-items: stretch;\n",
1019
+ " justify-content: center;\n",
1020
+ " background-color: var(--sklearn-color-background);\n",
1021
+ " position: relative;\n",
1022
+ "}\n",
1023
+ "\n",
1024
+ "#sk-container-id-1 div.sk-parallel-item {\n",
1025
+ " display: flex;\n",
1026
+ " flex-direction: column;\n",
1027
+ "}\n",
1028
+ "\n",
1029
+ "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
1030
+ " align-self: flex-end;\n",
1031
+ " width: 50%;\n",
1032
+ "}\n",
1033
+ "\n",
1034
+ "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
1035
+ " align-self: flex-start;\n",
1036
+ " width: 50%;\n",
1037
+ "}\n",
1038
+ "\n",
1039
+ "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
1040
+ " width: 0;\n",
1041
+ "}\n",
1042
+ "\n",
1043
+ "/* Serial-specific style estimator block */\n",
1044
+ "\n",
1045
+ "#sk-container-id-1 div.sk-serial {\n",
1046
+ " display: flex;\n",
1047
+ " flex-direction: column;\n",
1048
+ " align-items: center;\n",
1049
+ " background-color: var(--sklearn-color-background);\n",
1050
+ " padding-right: 1em;\n",
1051
+ " padding-left: 1em;\n",
1052
+ "}\n",
1053
+ "\n",
1054
+ "\n",
1055
+ "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
1056
+ "clickable and can be expanded/collapsed.\n",
1057
+ "- Pipeline and ColumnTransformer use this feature and define the default style\n",
1058
+ "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
1059
+ "*/\n",
1060
+ "\n",
1061
+ "/* Pipeline and ColumnTransformer style (default) */\n",
1062
+ "\n",
1063
+ "#sk-container-id-1 div.sk-toggleable {\n",
1064
+ " /* Default theme specific background. It is overwritten whether we have a\n",
1065
+ " specific estimator or a Pipeline/ColumnTransformer */\n",
1066
+ " background-color: var(--sklearn-color-background);\n",
1067
+ "}\n",
1068
+ "\n",
1069
+ "/* Toggleable label */\n",
1070
+ "#sk-container-id-1 label.sk-toggleable__label {\n",
1071
+ " cursor: pointer;\n",
1072
+ " display: block;\n",
1073
+ " width: 100%;\n",
1074
+ " margin-bottom: 0;\n",
1075
+ " padding: 0.5em;\n",
1076
+ " box-sizing: border-box;\n",
1077
+ " text-align: center;\n",
1078
+ "}\n",
1079
+ "\n",
1080
+ "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
1081
+ " /* Arrow on the left of the label */\n",
1082
+ " content: \"▸\";\n",
1083
+ " float: left;\n",
1084
+ " margin-right: 0.25em;\n",
1085
+ " color: var(--sklearn-color-icon);\n",
1086
+ "}\n",
1087
+ "\n",
1088
+ "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
1089
+ " color: var(--sklearn-color-text);\n",
1090
+ "}\n",
1091
+ "\n",
1092
+ "/* Toggleable content - dropdown */\n",
1093
+ "\n",
1094
+ "#sk-container-id-1 div.sk-toggleable__content {\n",
1095
+ " max-height: 0;\n",
1096
+ " max-width: 0;\n",
1097
+ " overflow: hidden;\n",
1098
+ " text-align: left;\n",
1099
+ " /* unfitted */\n",
1100
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
1101
+ "}\n",
1102
+ "\n",
1103
+ "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
1104
+ " /* fitted */\n",
1105
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
1106
+ "}\n",
1107
+ "\n",
1108
+ "#sk-container-id-1 div.sk-toggleable__content pre {\n",
1109
+ " margin: 0.2em;\n",
1110
+ " border-radius: 0.25em;\n",
1111
+ " color: var(--sklearn-color-text);\n",
1112
+ " /* unfitted */\n",
1113
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
1114
+ "}\n",
1115
+ "\n",
1116
+ "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
1117
+ " /* unfitted */\n",
1118
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
1119
+ "}\n",
1120
+ "\n",
1121
+ "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
1122
+ " /* Expand drop-down */\n",
1123
+ " max-height: 200px;\n",
1124
+ " max-width: 100%;\n",
1125
+ " overflow: auto;\n",
1126
+ "}\n",
1127
+ "\n",
1128
+ "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
1129
+ " content: \"▾\";\n",
1130
+ "}\n",
1131
+ "\n",
1132
+ "/* Pipeline/ColumnTransformer-specific style */\n",
1133
+ "\n",
1134
+ "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
1135
+ " color: var(--sklearn-color-text);\n",
1136
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
1137
+ "}\n",
1138
+ "\n",
1139
+ "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
1140
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
1141
+ "}\n",
1142
+ "\n",
1143
+ "/* Estimator-specific style */\n",
1144
+ "\n",
1145
+ "/* Colorize estimator box */\n",
1146
+ "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
1147
+ " /* unfitted */\n",
1148
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
1149
+ "}\n",
1150
+ "\n",
1151
+ "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
1152
+ " /* fitted */\n",
1153
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
1154
+ "}\n",
1155
+ "\n",
1156
+ "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
1157
+ "#sk-container-id-1 div.sk-label label {\n",
1158
+ " /* The background is the default theme color */\n",
1159
+ " color: var(--sklearn-color-text-on-default-background);\n",
1160
+ "}\n",
1161
+ "\n",
1162
+ "/* On hover, darken the color of the background */\n",
1163
+ "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
1164
+ " color: var(--sklearn-color-text);\n",
1165
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
1166
+ "}\n",
1167
+ "\n",
1168
+ "/* Label box, darken color on hover, fitted */\n",
1169
+ "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
1170
+ " color: var(--sklearn-color-text);\n",
1171
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
1172
+ "}\n",
1173
+ "\n",
1174
+ "/* Estimator label */\n",
1175
+ "\n",
1176
+ "#sk-container-id-1 div.sk-label label {\n",
1177
+ " font-family: monospace;\n",
1178
+ " font-weight: bold;\n",
1179
+ " display: inline-block;\n",
1180
+ " line-height: 1.2em;\n",
1181
+ "}\n",
1182
+ "\n",
1183
+ "#sk-container-id-1 div.sk-label-container {\n",
1184
+ " text-align: center;\n",
1185
+ "}\n",
1186
+ "\n",
1187
+ "/* Estimator-specific */\n",
1188
+ "#sk-container-id-1 div.sk-estimator {\n",
1189
+ " font-family: monospace;\n",
1190
+ " border: 1px dotted var(--sklearn-color-border-box);\n",
1191
+ " border-radius: 0.25em;\n",
1192
+ " box-sizing: border-box;\n",
1193
+ " margin-bottom: 0.5em;\n",
1194
+ " /* unfitted */\n",
1195
+ " background-color: var(--sklearn-color-unfitted-level-0);\n",
1196
+ "}\n",
1197
+ "\n",
1198
+ "#sk-container-id-1 div.sk-estimator.fitted {\n",
1199
+ " /* fitted */\n",
1200
+ " background-color: var(--sklearn-color-fitted-level-0);\n",
1201
+ "}\n",
1202
+ "\n",
1203
+ "/* on hover */\n",
1204
+ "#sk-container-id-1 div.sk-estimator:hover {\n",
1205
+ " /* unfitted */\n",
1206
+ " background-color: var(--sklearn-color-unfitted-level-2);\n",
1207
+ "}\n",
1208
+ "\n",
1209
+ "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
1210
+ " /* fitted */\n",
1211
+ " background-color: var(--sklearn-color-fitted-level-2);\n",
1212
+ "}\n",
1213
+ "\n",
1214
+ "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
1215
+ "\n",
1216
+ "/* Common style for \"i\" and \"?\" */\n",
1217
+ "\n",
1218
+ ".sk-estimator-doc-link,\n",
1219
+ "a:link.sk-estimator-doc-link,\n",
1220
+ "a:visited.sk-estimator-doc-link {\n",
1221
+ " float: right;\n",
1222
+ " font-size: smaller;\n",
1223
+ " line-height: 1em;\n",
1224
+ " font-family: monospace;\n",
1225
+ " background-color: var(--sklearn-color-background);\n",
1226
+ " border-radius: 1em;\n",
1227
+ " height: 1em;\n",
1228
+ " width: 1em;\n",
1229
+ " text-decoration: none !important;\n",
1230
+ " margin-left: 1ex;\n",
1231
+ " /* unfitted */\n",
1232
+ " border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
1233
+ " color: var(--sklearn-color-unfitted-level-1);\n",
1234
+ "}\n",
1235
+ "\n",
1236
+ ".sk-estimator-doc-link.fitted,\n",
1237
+ "a:link.sk-estimator-doc-link.fitted,\n",
1238
+ "a:visited.sk-estimator-doc-link.fitted {\n",
1239
+ " /* fitted */\n",
1240
+ " border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
1241
+ " color: var(--sklearn-color-fitted-level-1);\n",
1242
+ "}\n",
1243
+ "\n",
1244
+ "/* On hover */\n",
1245
+ "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
1246
+ ".sk-estimator-doc-link:hover,\n",
1247
+ "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
1248
+ ".sk-estimator-doc-link:hover {\n",
1249
+ " /* unfitted */\n",
1250
+ " background-color: var(--sklearn-color-unfitted-level-3);\n",
1251
+ " color: var(--sklearn-color-background);\n",
1252
+ " text-decoration: none;\n",
1253
+ "}\n",
1254
+ "\n",
1255
+ "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
1256
+ ".sk-estimator-doc-link.fitted:hover,\n",
1257
+ "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
1258
+ ".sk-estimator-doc-link.fitted:hover {\n",
1259
+ " /* fitted */\n",
1260
+ " background-color: var(--sklearn-color-fitted-level-3);\n",
1261
+ " color: var(--sklearn-color-background);\n",
1262
+ " text-decoration: none;\n",
1263
+ "}\n",
1264
+ "\n",
1265
+ "/* Span, style for the box shown on hovering the info icon */\n",
1266
+ ".sk-estimator-doc-link span {\n",
1267
+ " display: none;\n",
1268
+ " z-index: 9999;\n",
1269
+ " position: relative;\n",
1270
+ " font-weight: normal;\n",
1271
+ " right: .2ex;\n",
1272
+ " padding: .5ex;\n",
1273
+ " margin: .5ex;\n",
1274
+ " width: min-content;\n",
1275
+ " min-width: 20ex;\n",
1276
+ " max-width: 50ex;\n",
1277
+ " color: var(--sklearn-color-text);\n",
1278
+ " box-shadow: 2pt 2pt 4pt #999;\n",
1279
+ " /* unfitted */\n",
1280
+ " background: var(--sklearn-color-unfitted-level-0);\n",
1281
+ " border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
1282
+ "}\n",
1283
+ "\n",
1284
+ ".sk-estimator-doc-link.fitted span {\n",
1285
+ " /* fitted */\n",
1286
+ " background: var(--sklearn-color-fitted-level-0);\n",
1287
+ " border: var(--sklearn-color-fitted-level-3);\n",
1288
+ "}\n",
1289
+ "\n",
1290
+ ".sk-estimator-doc-link:hover span {\n",
1291
+ " display: block;\n",
1292
+ "}\n",
1293
+ "\n",
1294
+ "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
1295
+ "\n",
1296
+ "#sk-container-id-1 a.estimator_doc_link {\n",
1297
+ " float: right;\n",
1298
+ " font-size: 1rem;\n",
1299
+ " line-height: 1em;\n",
1300
+ " font-family: monospace;\n",
1301
+ " background-color: var(--sklearn-color-background);\n",
1302
+ " border-radius: 1rem;\n",
1303
+ " height: 1rem;\n",
1304
+ " width: 1rem;\n",
1305
+ " text-decoration: none;\n",
1306
+ " /* unfitted */\n",
1307
+ " color: var(--sklearn-color-unfitted-level-1);\n",
1308
+ " border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
1309
+ "}\n",
1310
+ "\n",
1311
+ "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
1312
+ " /* fitted */\n",
1313
+ " border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
1314
+ " color: var(--sklearn-color-fitted-level-1);\n",
1315
+ "}\n",
1316
+ "\n",
1317
+ "/* On hover */\n",
1318
+ "#sk-container-id-1 a.estimator_doc_link:hover {\n",
1319
+ " /* unfitted */\n",
1320
+ " background-color: var(--sklearn-color-unfitted-level-3);\n",
1321
+ " color: var(--sklearn-color-background);\n",
1322
+ " text-decoration: none;\n",
1323
+ "}\n",
1324
+ "\n",
1325
+ "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
1326
+ " /* fitted */\n",
1327
+ " background-color: var(--sklearn-color-fitted-level-3);\n",
1328
+ "}\n",
1329
+ "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Pipeline(steps=[(&#x27;preprocessor&#x27;, TextPreprocessor()),\n",
1330
+ " (&#x27;vectorizer&#x27;,\n",
1331
+ " TfidfVectorizer(max_df=0.9, min_df=500,\n",
1332
+ " stop_words=[&#x27;и&#x27;, &#x27;в&#x27;, &#x27;во&#x27;, &#x27;не&#x27;, &#x27;что&#x27;, &#x27;он&#x27;,\n",
1333
+ " &#x27;на&#x27;, &#x27;я&#x27;, &#x27;с&#x27;, &#x27;со&#x27;, &#x27;как&#x27;, &#x27;а&#x27;,\n",
1334
+ " &#x27;то&#x27;, &#x27;все&#x27;, &#x27;она&#x27;, &#x27;так&#x27;, &#x27;его&#x27;,\n",
1335
+ " &#x27;но&#x27;, &#x27;да&#x27;, &#x27;ты&#x27;, &#x27;к&#x27;, &#x27;у&#x27;, &#x27;же&#x27;,\n",
1336
+ " &#x27;вы&#x27;, &#x27;за&#x27;, &#x27;бы&#x27;, &#x27;по&#x27;, &#x27;только&#x27;,\n",
1337
+ " &#x27;ее&#x27;, &#x27;мне&#x27;, ...])),\n",
1338
+ " (&#x27;lsa&#x27;,\n",
1339
+ " Pipeline(steps=[(&#x27;truncatedsvd&#x27;,\n",
1340
+ " TruncatedSVD(n_components=500)),\n",
1341
+ " (&#x27;normalizer&#x27;, Normalizer(copy=False))])),\n",
1342
+ " (&#x27;classifier&#x27;, LogisticRegression())])</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" ><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;&nbsp;Pipeline<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for Pipeline</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;preprocessor&#x27;, TextPreprocessor()),\n",
1343
+ " (&#x27;vectorizer&#x27;,\n",
1344
+ " TfidfVectorizer(max_df=0.9, min_df=500,\n",
1345
+ " stop_words=[&#x27;и&#x27;, &#x27;в&#x27;, &#x27;во&#x27;, &#x27;не&#x27;, &#x27;что&#x27;, &#x27;он&#x27;,\n",
1346
+ " &#x27;на&#x27;, &#x27;я&#x27;, &#x27;с&#x27;, &#x27;со&#x27;, &#x27;как&#x27;, &#x27;а&#x27;,\n",
1347
+ " &#x27;то&#x27;, &#x27;все&#x27;, &#x27;она&#x27;, &#x27;так&#x27;, &#x27;его&#x27;,\n",
1348
+ " &#x27;но&#x27;, &#x27;да&#x27;, &#x27;ты&#x27;, &#x27;к&#x27;, &#x27;у&#x27;, &#x27;же&#x27;,\n",
1349
+ " &#x27;вы&#x27;, &#x27;за&#x27;, &#x27;бы&#x27;, &#x27;по&#x27;, &#x27;только&#x27;,\n",
1350
+ " &#x27;ее&#x27;, &#x27;мне&#x27;, ...])),\n",
1351
+ " (&#x27;lsa&#x27;,\n",
1352
+ " Pipeline(steps=[(&#x27;truncatedsvd&#x27;,\n",
1353
+ " TruncatedSVD(n_components=500)),\n",
1354
+ " (&#x27;normalizer&#x27;, Normalizer(copy=False))])),\n",
1355
+ " (&#x27;classifier&#x27;, LogisticRegression())])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-2\" type=\"checkbox\" ><label for=\"sk-estimator-id-2\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">TextPreprocessor</label><div class=\"sk-toggleable__content fitted\"><pre>TextPreprocessor()</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-3\" type=\"checkbox\" ><label for=\"sk-estimator-id-3\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;TfidfVectorizer<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html\">?<span>Documentation for TfidfVectorizer</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>TfidfVectorizer(max_df=0.9, min_df=500,\n",
1356
+ " stop_words=[&#x27;и&#x27;, &#x27;в&#x27;, &#x27;во&#x27;, &#x27;не&#x27;, &#x27;что&#x27;, &#x27;он&#x27;, &#x27;на&#x27;, &#x27;я&#x27;, &#x27;с&#x27;,\n",
1357
+ " &#x27;со&#x27;, &#x27;как&#x27;, &#x27;а&#x27;, &#x27;то&#x27;, &#x27;все&#x27;, &#x27;она&#x27;, &#x27;так&#x27;, &#x27;его&#x27;,\n",
1358
+ " &#x27;но&#x27;, &#x27;да&#x27;, &#x27;ты&#x27;, &#x27;к&#x27;, &#x27;у&#x27;, &#x27;же&#x27;, &#x27;вы&#x27;, &#x27;за&#x27;, &#x27;бы&#x27;,\n",
1359
+ " &#x27;по&#x27;, &#x27;только&#x27;, &#x27;ее&#x27;, &#x27;мне&#x27;, ...])</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-label-container\"><div class=\"sk-label fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-4\" type=\"checkbox\" ><label for=\"sk-estimator-id-4\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;lsa: Pipeline<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.pipeline.Pipeline.html\">?<span>Documentation for lsa: Pipeline</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>Pipeline(steps=[(&#x27;truncatedsvd&#x27;, TruncatedSVD(n_components=500)),\n",
1360
+ " (&#x27;normalizer&#x27;, Normalizer(copy=False))])</pre></div> </div></div><div class=\"sk-serial\"><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-5\" type=\"checkbox\" ><label for=\"sk-estimator-id-5\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;TruncatedSVD<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.decomposition.TruncatedSVD.html\">?<span>Documentation for TruncatedSVD</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>TruncatedSVD(n_components=500)</pre></div> </div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-6\" type=\"checkbox\" ><label for=\"sk-estimator-id-6\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;Normalizer<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.preprocessing.Normalizer.html\">?<span>Documentation for Normalizer</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>Normalizer(copy=False)</pre></div> </div></div></div></div><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-7\" type=\"checkbox\" ><label for=\"sk-estimator-id-7\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow fitted\">&nbsp;LogisticRegression<a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.4/modules/generated/sklearn.linear_model.LogisticRegression.html\">?<span>Documentation for LogisticRegression</span></a></label><div class=\"sk-toggleable__content fitted\"><pre>LogisticRegression()</pre></div> </div></div></div></div></div></div>"
1361
+ ],
1362
+ "text/plain": [
1363
+ "Pipeline(steps=[('preprocessor', TextPreprocessor()),\n",
1364
+ " ('vectorizer',\n",
1365
+ " TfidfVectorizer(max_df=0.9, min_df=500,\n",
1366
+ " stop_words=['и', 'в', 'во', 'не', 'что', 'он',\n",
1367
+ " 'на', 'я', 'с', 'со', 'как', 'а',\n",
1368
+ " 'то', 'все', 'она', 'так', 'его',\n",
1369
+ " 'но', 'да', 'ты', 'к', 'у', 'же',\n",
1370
+ " 'вы', 'за', 'бы', 'по', 'только',\n",
1371
+ " 'ее', 'мне', ...])),\n",
1372
+ " ('lsa',\n",
1373
+ " Pipeline(steps=[('truncatedsvd',\n",
1374
+ " TruncatedSVD(n_components=500)),\n",
1375
+ " ('normalizer', Normalizer(copy=False))])),\n",
1376
+ " ('classifier', LogisticRegression())])"
1377
+ ]
1378
+ },
1379
+ "execution_count": 54,
1380
+ "metadata": {},
1381
+ "output_type": "execute_result"
1382
+ }
1383
+ ],
1384
+ "source": [
1385
+ "import re\n",
1386
+ "import pandas as pd\n",
1387
+ "import numpy as np\n",
1388
+ "from sklearn.base import BaseEstimator, TransformerMixin\n",
1389
+ "from sklearn.feature_extraction.text import TfidfVectorizer\n",
1390
+ "from sklearn.decomposition import TruncatedSVD\n",
1391
+ "from sklearn.pipeline import Pipeline, FeatureUnion\n",
1392
+ "from sklearn.linear_model import LogisticRegression\n",
1393
+ "from sklearn.preprocessing import Normalizer\n",
1394
+ "import joblib\n",
1395
+ "import nltk\n",
1396
+ "from nltk.corpus import stopwords\n",
1397
+ "from pymorphy2 import MorphAnalyzer\n",
1398
+ "\n",
1399
+ "nltk.download('stopwords')\n",
1400
+ "nltk.download('punkt')\n",
1401
+ "\n",
1402
+ "class TextPreprocessor(BaseEstimator, TransformerMixin):\n",
1403
+ " def __init__(self):\n",
1404
+ " self.stop_words = set(stopwords.words('russian'))\n",
1405
+ " self.morph = MorphAnalyzer()\n",
1406
+ "\n",
1407
+ " def preprocess_text(self, text):\n",
1408
+ " # Удаление всего, что не является буквами или знаками препинания\n",
1409
+ " clean_pattern = re.compile(r'[^a-zA-Zа-яА-ЯёЁ0-9.,!?;:\\s]')\n",
1410
+ " text = clean_pattern.sub('', text)\n",
1411
+ " url_pattern = re.compile(r'http\\S+|www\\S+|https\\S+')\n",
1412
+ " text = url_pattern.sub(r'', text)\n",
1413
+ " text = text.translate(str.maketrans('', '', string.punctuation))\n",
1414
+ " text = text.lower()\n",
1415
+ " tokens = text.split()\n",
1416
+ " lemmatized_text = ' '.join([self.morph.parse(word)[0].normal_form for word in tokens if word not in self.stop_words])\n",
1417
+ " return lemmatized_text\n",
1418
+ "\n",
1419
+ " def fit(self, X, y=None):\n",
1420
+ " return self\n",
1421
+ "\n",
1422
+ " def transform(self, X, y=None):\n",
1423
+ " return X.apply(self.preprocess_text)\n",
1424
+ "\n",
1425
+ "\n",
1426
+ "# Load and preprocess the dataset\n",
1427
+ "df = pd.read_json('data/healthcare_facilities_reviews.jsonl', lines=True)\n",
1428
+ "df = df[['sentiment', 'content']]\n",
1429
+ "df['cleaned_text'] = df['content'].apply(TextPreprocessor().preprocess_text)\n",
1430
+ "df['sentiment'] = df['sentiment'].apply(lambda x: 1 if x == 'negative' else 0)\n",
1431
+ "\n",
1432
+ "# Split the dataset (this is only for training purposes)\n",
1433
+ "from sklearn.model_selection import train_test_split\n",
1434
+ "train_df, test_df = train_test_split(df, test_size=0.2, random_state=42)\n",
1435
+ "\n",
1436
+ "# Create the pipeline\n",
1437
+ "vectorizer = TfidfVectorizer(\n",
1438
+ " max_df=0.9,\n",
1439
+ " min_df=500,\n",
1440
+ " stop_words=stopwords.words('russian')\n",
1441
+ ")\n",
1442
+ "\n",
1443
+ "lsa = TruncatedSVD(n_components=500)\n",
1444
+ "\n",
1445
+ "pipeline = Pipeline([\n",
1446
+ " ('preprocessor', TextPreprocessor()),\n",
1447
+ " ('vectorizer', vectorizer),\n",
1448
+ " ('lsa', make_pipeline(lsa, Normalizer(copy=False))),\n",
1449
+ " ('classifier', LogisticRegression())\n",
1450
+ "])\n",
1451
+ "\n",
1452
+ "# Train the model\n",
1453
+ "X_train = train_df['cleaned_text']\n",
1454
+ "y_train = train_df['sentiment']\n",
1455
+ "pipeline.fit(X_train, y_train)\n",
1456
+ "\n",
1457
+ "# Save the model\n",
1458
+ "# joblib.dump(pipeline, 'logistic_regression_pipeline.pkl')\n"
1459
+ ]
1460
+ },
1461
+ {
1462
+ "cell_type": "code",
1463
+ "execution_count": 55,
1464
+ "metadata": {},
1465
+ "outputs": [
1466
+ {
1467
+ "data": {
1468
+ "text/plain": [
1469
+ "['logistic_regression_pipeline.pkl']"
1470
+ ]
1471
+ },
1472
+ "execution_count": 55,
1473
+ "metadata": {},
1474
+ "output_type": "execute_result"
1475
+ }
1476
+ ],
1477
+ "source": [
1478
+ "# Save the model for future use\n",
1479
+ "joblib.dump(pipeline, 'logistic_regression_pipeline.pkl')"
1480
+ ]
1481
+ },
1482
+ {
1483
+ "cell_type": "code",
1484
+ "execution_count": 56,
1485
+ "metadata": {},
1486
+ "outputs": [],
1487
+ "source": [
1488
+ "# Load the model (if not already loaded)\n",
1489
+ "pipeline_test= joblib.load('logistic_regression_pipeline.pkl')"
1490
+ ]
1491
+ },
1492
+ {
1493
+ "cell_type": "code",
1494
+ "execution_count": 61,
1495
+ "metadata": {},
1496
+ "outputs": [
1497
+ {
1498
+ "name": "stdout",
1499
+ "output_type": "stream",
1500
+ "text": [
1501
+ "Predicted class: 1\n",
1502
+ "Predicted proba: 0.898\n"
1503
+ ]
1504
+ }
1505
+ ],
1506
+ "source": [
1507
+ "# Sample text for prediction\n",
1508
+ "sample_text = \"Ужасная клиника, обслуживание из рук вон плохое, хотеловь бы выразить свое разочарование данным заведением. Советую обходить его мимо.\"\n",
1509
+ "\n",
1510
+ "# Use the pipeline to predict the class\n",
1511
+ "predicted_class = pipeline_test.predict(pd.Series([sample_text]))\n",
1512
+ "predicted_prob = pipeline_test.predict_proba(pd.Series([sample_text]))\n",
1513
+ "print(f\"Predicted class: {predicted_class[0]}\")\n",
1514
+ "print(f\"Predicted proba: {round(predicted_prob[0][1], 3)}\")"
1515
+ ]
1516
+ }
1517
+ ],
1518
+ "metadata": {
1519
+ "kernelspec": {
1520
+ "display_name": "base",
1521
+ "language": "python",
1522
+ "name": "python3"
1523
+ },
1524
+ "language_info": {
1525
+ "codemirror_mode": {
1526
+ "name": "ipython",
1527
+ "version": 3
1528
+ },
1529
+ "file_extension": ".py",
1530
+ "mimetype": "text/x-python",
1531
+ "name": "python",
1532
+ "nbconvert_exporter": "python",
1533
+ "pygments_lexer": "ipython3",
1534
+ "version": "3.10.14"
1535
+ }
1536
+ },
1537
+ "nbformat": 4,
1538
+ "nbformat_minor": 2
1539
+ }
pages/policlinic.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import joblib
3
+ import pandas as pd
4
+
5
+ # Load the trained pipeline
6
+ pipeline = joblib.load('logistic_regression_pipeline.pkl')
7
+
8
+ # Streamlit application
9
+ st.title('Классификация отзывов на русском языке')
10
+
11
+ input_text = st.text_area('Введите текст отзыва')
12
+
13
+ if st.button('Предсказать'):
14
+ prediction = pipeline.predict(pd.Series([input_text]))
15
+ st.write(f'Предсказанный класс с помощью логрег: {prediction[0]}')