{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Лабораторная 6: Анализ текстов. SVM\n",
"\n",
"В этом задании мы должны научить машину понимать тексты. В файле recs.txt находятся отзывы о разных фильмах. Наша модель машинного обучения должна проанализировать отзыв и ответить на простой вопрос: понравился ли пользователю просмотренный фильм.\n",
"\n",
"1. Подключите необходимые для работы пакеты: pandas as pd, numpy as np, nltk, re, все функции из sklearn"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2. Увеличьте ширину выводимой информации в DataFrame (на это понадобится для показа текстов отзывав):\n",
"pd.set_option('max_colwidth',600)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"3. Прочтите данные из файла recs.txt, в качестве разделителя (параметр sep) там выступает строка \"\\\\-\\\\-\\\\|\\\\|\\\\|\\\\-\\\\-\", кодировка (параметр encoding) - 'utf-8'.\n",
"Выведите три первых строки таблицы. Какое отношение (Sentiment) у авторов отзывов к просмотренным фильмам?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"4. Чтобы преобразовать тексты в наборы признаков методом bag-of-words мы должны сначала профильтровать текст, оставив только значащие слова. Скачайте из корпуса набор незначащих слов для фильтрации командой nltk.download() (в появившемся окне вкладка Corpora, пункт stopwords). "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"5. Импортируйте список незначащих слов командами \n",
"\n",
"```python\n",
"from nltk.corpus import stopwords\n",
"stopwords = set(stopwords.words(\"russian\"))\n",
"```\n",
"и выведите его на экран."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"6. Определите функцию фильтрации текста:\n",
"\n",
"```python\n",
"def review_to_words( review_text ):\n",
" review_text = review_text.replace('ё','е')\n",
" review_text = review_text.replace('Ё','Е')\n",
" # 1. Удаляем все, кроме букв\n",
" letters_only = re.sub(\"[^а-яА-Я]\", \" \", review_text) \n",
" # 2. Делаем все буквы строчными и создаем массив слов\n",
" words = letters_only.lower().split() \n",
" # 3. Удаляем незначащие слова\n",
" meaningful_words = [w for w in words if not w in stopwords]\n",
" # 4. Формируем текст, объединяя слова через пробел\n",
" return( \" \".join( meaningful_words ))\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"7. Скопируйте базу данных отзывов с помощью метода copy() в новую переменную и примените к отзывам функцию фильтрации: .apply(lambda s: review_to_words(s)).\n",
"Выведите на экран первые три строчки преобразованной базы данных"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"8. Запустите преобразователь текстового признака в «bag of words» с помощью класса CountVectorizer библиотеки sklearn.feature_extraction.text. \n",
"\n",
"В конструкторе класса укажите параметры: analyzer = \"word\", tokenizer = None, preprocessor = None, stop_words = None, max_features = 50000, binary = True\n",
"\n",
"Вызовите метод обучения (построения словаря) и преобразования текстов: fit_transform. Результат присвойте новой переменной bagOfWords.\n",
"\n",
"Сохраните порядок слов в словаре (метод .get_feature_names()) в переменную vocabulary."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"9. Теперь в наших матрицах объектов-признаков 50 тысяч столбцов и в сумме 100 тысяч строк. Один элемент матрицы хранится в типе double и занимает 8 байт, значит суммарный объем матрицы равен 40 Гб. Проверьте по диспетчеру задач (системный монитор в Linux), сколько занимает памяти ваша программа и напишите в комментариях. Если размеры не согласуются, объясните это в комментариях."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"10. Разбейте выборку bagOfWords на две части: обучающую (строки до 50000) и проверочную (строки >= 50000). Назовите их bagOfWordsTrain и bagOfWordsTest"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"11. Сконструируйте машину опорных векторов svm.LinearSVC с параметрами C=1, fit_intercept=False и присвойте ее переменной SVM.\n",
"\n",
"Натренируйте ее на обучающей выборке и с помощью метода .score(x,y) вычислите процент правильных предсказаний для тестовой выборки.\n",
"\n",
"Подберите важность суммы нарушений C, чтобы SVM работала лучше всего"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"12. Выведите на экран 20 слов, которые больше всего голосуют за позитивность отзыва и 20 — за негативность вместе с соответствующими им коэффициентами натренированной линейной функции:\n",
"\n",
"```python\n",
"ind = np.argsort(SVM.coef_[0])\n",
"for i in range(20):\n",
" print(SVM.coef_[0][ind[i]], vocabulary[ind[i]])\n",
"print(\"\\n\")\n",
"for i in range(20):\n",
" print(SVM.coef_[0][ind[-i-1]], vocabulary[ind[-i-1]]) \n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"13. Какой коэффициент соответствует словам: 'критика', 'странно', 'понимаю', 'деньги', 'даже' и еще 5 ваших слов по выбору. За что они голосуют: позитивность или негативность отзыва?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"14. Вычислите выступы, найдите и выведете на экран отзывы с минимальным и максимальным выступом, величину выступа, величину предсказания и сентиментность отзыва. \n",
"\n",
"```python\n",
"prediction = SVM.decision_function(bagOfWordsTest)\n",
"margins = np.multiply(prediction, data.loc[50000:]['Sentiment'].as_matrix())\n",
"ind = np.argsort(margins)\n",
"i = ind[-1] + 50000\n",
"print('Величина выступа = ', margins[ind[-1]])\n",
"print('Величина предсказания = ', prediction[ind[-1]])\n",
"print('Сентиментность отзыва = ', data.loc[i,'Sentiment'])\n",
"print('\\n')\n",
"print(data.loc[i,'Text'])\n",
"print(\"\\n\")\n",
"i = ind[0] + 50000\n",
"print('Величина выступа = ', margins[ind[0]])\n",
"print('Величина предсказания = ', prediction[ind[0]])\n",
"print('Сентиментность отзыва = ', data.loc[i,'Sentiment'])\n",
"print('\\n')\n",
"print(data.loc[i,'Text'])\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"15. Нормализуйте признаки перед разбиением выборки на Train и Test так, чтобы вместо 0/1 стояли частоты употребления слов, деленные на длину отзыва. Подберите наилучшую константу C и опишите, как изменятся отзывы с минимальным и максимальным выступом? Что лучше: не нормализованные или нормализованные признаки? Почему?\n",
"\n",
"Нужно установить binary = False в CountVectorizer и добавить после fit_transform\n",
"```python\n",
"bagOfWords = preprocessing.normalize(bagOfWords, norm='l1')\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"16. Объясните в комментариях, почему найденный отзыв с очень отрицательным выступом имеет такой маленький выступ, а другой найденный — такой большой.\n",
"\n",
"Для объяснения отступов вам возможно пригодится код, который печатает коэффициенты wi линейной функции, значения соответствующих признаков и соответствующие слова. И все это делается в порядке убывания модуля произведения wixi:\n",
"```python\n",
"k = ind[0]\n",
"ind2 = np.argsort(np.abs(np.multiply(SVM.coef_[0], bagOfWordsTest[k].todense()))).reshape(-1,1)\n",
"s = 0\n",
"for i in range((bagOfWordsTest[k]!=0).sum()):\n",
" ii = ind2[-i-1].item()\n",
" print('wi='+str(SVM.coef_[0][ii]), 'xi='+str(bagOfWordsTest[k,ii]), vocabulary[ii])\n",
" s += SVM.coef_[0][ii]*bagOfWordsTest[k,ii]\n",
"print('Проверка:',s) \n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}