{ "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 }