Дата выдачи: 18.03.2016
Срок сдачи: 5.04.2016 09:00MSK
Домашнее задание направлено на реализацию наивного байесвского классификатора для многоклассового случая.
Каждая из задач имеет определенную «стоимость» (указана в скобках около задачи). Максимально допустимая оценка за работу — 10 баллов. Обратите внимание, что только за реализацию функций без подтверждения их корректной работы оценка выставляться не будет.
Сдавать задание после указанного срока сдачи нельзя. При выставлении неполного балла за задание в связи с наличием ошибок на усмотрение проверяющего предусмотрена возможность исправить задание на указанных в ответном письме условиях.
Задание выполняется САМОСТОЯТЕЛЬНО. «Похожие» решения считаются плагиатом и все задействованные студенты (в том числе те, у кого списали) не могут получить за него больше 0 баллов. Если вы нашли решение какого-то из заданий (или его часть) в открытом источнике, необходимо указать ссылку на этот источник в отдельном блоке в конце данного ноутбука (скорее всего вы будете не единственным, кто это нашел, поэтому чтобы исключить подозрение в плагиате, необходима ссылка на источник).
Для сдачи задания переименуйте получившийся файл *.ipynb в соответствии со следующим форматом: HW3_Username.ipynb, где Username — Ваша фамилия на латинице (например, HW3_Zinnurova.ipynb). Далее отправьте этот файл на используемую в Вашей группе почту курса (hse.minor.dm+13@gmail.com для ИАД-13).
Обучение методом наивного Байеса основывается на достаточно сильном предположении, что все признаки независимы в совокупности. По формуле Байеса $$P(y|x) = P(y|(x^1,\dots,x^d))=\frac{P(y)P(x^1,\dots,x^d|y)}{P(x^1,\dots,x^d)}.$$ В предположении, что признаки независимы, получаем, что $$P(y|x^1,\dots,x^d)=\frac{P(y)\prod_{i=1}^d P(x^i|y)}{P(x^1,\dots,x^d)}$$ Т.к. $P(x^1,\dots,x^d)$ не зависит от $y$, то формула наивного байесовского классификатора записывается следующим образом:
$$\hat y (x) = \arg\max_y P(y)\prod_{i=1}^d P(x^d|y).$$Библиотека sklearn
поддерживает несколько реализаций наивного Байеса: sklearn.naive_bayes.GaussianNB
, sklearn.naive_bayes.MultinomialNB
и др.
from sklearn.cross_validation import train_test_split
from sklearn.datasets import fetch_20newsgroups
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
import numpy as np
Данными для задачи будет выступать подмножество одного из популярных датасетов 20 News Groups, который является набором статей, разбитых по категориям (темам).
Пример статьи на тему космоса:
From: MUNIZB%RWTMS2.decnet@rockwell.com ("RWTMS2::MUNIZB")
Subject: Alaska Pipeline and Space Station!
X-Added: Forwarded by Space Digest
Organization: [via International Space University]
Original-Sender: isu@VACATION.VENARI.CS.CMU.EDU
Distribution: sci
Lines: 16
on Date: 01 Apr 93 18:03:12 GMT, Ralph Buttigieg <ralph.buttigieg@f635.n713.z3.fido.zeta.org.au> writes:
Why can't the government just be a tennant? Private commercial concerns could just build a space station system and charge rent to the government financed researchers wanting to use it. I believe that this was the thought behind the Industrial Space Facility. I don't remember all the details, but I think Space Services (?) wanted NASA to sign an anchor tenancy deal in order to help secure some venture capital but NASA didn't like the deal. (I'm sure I'll hear about it if I'm wrong!)
Disclaimer: Opinions stated are solely my own (unless I change my mind).
Ben Muniz
MUNIZB%RWTMS2.decnet@consrt.rockwell.com w(818)586-3578 Space Station
Freedom:Rocketdyne/Rockwell:Structural Loads and Dynamics "Man will not fly for fifty years": Wilbur to Orville Wright, 1901
Можно заметить, что данные никак не предобработаны, пунктуация и служебная информация сохранены.
Задание 1. (2 балла) Выберите 2 произвольные категории текстов из списка ниже, с которыми вы будете работать в рамках данного задания. В переменной text находится список статей выборки, в переменной y — вектор ответов для них. Обратите внимание, что в качестве ответов выступают индексы тем в списке theme_list, а не сами названия тем. Выберите тексты, относящиеся к выбранным Вами темам (и сохраните сами тексты и вектор ответов для них в переменные text и y соответственно) и случайным образом, в пропорции 70/30, разделите наборы текстов на обучающую и контрольную выборки. В результате выполнения данного задания у вас должно получится 5 переменных: text, text_train, text_test, y_train, y_test.
Обратите внимание, что данные уже "перемешаны", поэтому можно проивести разделение аналогично п. 5' ДЗ №2.
# Список новостных заголовков
theme_list =
['alt.atheism',
'comp.graphics',
'comp.os.ms-windows.misc',
'comp.sys.ibm.pc.hardware',
'comp.sys.mac.hardware',
'comp.windows.x',
'misc.forsale',
'rec.autos',
'rec.motorcycles',
'rec.sport.baseball',
'rec.sport.hockey',
'sci.crypt',
'sci.electronics',
'sci.med',
'sci.space',
'soc.religion.christian',
'talk.politics.guns',
'talk.politics.mideast',
'talk.politics.misc',
'talk.religion.misc']
dataset = fetch_20newsgroups(subset = 'train')
perm = np.random.permutation(pd.Series(dataset.data).index)
text = pd.Series(dataset.data).reindex(perm)
y = pd.Series(dataset.target).reindex(perm)
## Your code here
Задание 2. (2 балла) На данный момент данные имеют текстовый вид, и не очень понятно, как с ними работать дальше. В этом задании мы приведем их к числовому представлению. Для каждого текста признаками будут являться количество вхождений конкретного слова в данный текст. Например, для выборки из двух текстов {"one two two", "one three two"} матрицей "объект-признак" будет являться
$$\left[ \begin{matrix} 1 & 2 & 0 \\ 1 & 1 & 1 \end{matrix} \right],$$где номер строки в матрице совпадает с номером текста в выборке, признаки обозначают количество вхождений слова "one", "two" или "three" соответственно (слева направо).
CountVectorizer — объект, позволяющий привести выборку, состоящую из текстов, к указанному выше виду. Необходимый объект уже создан в ячейке ниже.
Вызовите метод fit объекта vectorizer из ячейки ниже, передав в качестве параметра набор текстов text, — таким образом он "запомнит" все имеющиеся в выборке слова. Затем дважды вызовите метод transform, передав ему параметры text_train и text_test соответственно — таким образом вы получите необходимое представление ваших обучающей и контрольной выборок. Сохраните их в переменные X_train и X_test соответственно — таким образом, вы получили 2 матрицы "объекта-признак". Обратите внимание, что эти матрицы являются сильно разреженными, поэтому вызовите для каждой из них метод .toarray(), чтобы привести их в типу np.ndarray.
vectorizer = CountVectorizer(analyzer='word', stop_words='english', lowercase=True)
## Your code here
Задание 3. (3 балла) По матрице X_train выведите 50 наиболее часто встречающихся слов.
Для этого вам сначала необходимо сложить все строки X_train, чтобы найти общее количество вхождений для каждого слова. Далее используйте метод argsort() (выполняет сортировку вектора по возрастанию, однако возвращает вектор не значений, а их индексов). Таким образом, 50 последних значений в получившемся векторе — это номера признаков, которые отвечают за самые частые слова. Теперь, чтобы получить сами слова, используйте метод vectorizer.get_feature_names() (возвращает список слов в том порядке, в котором расположены отвечающие им столбцы в матрице X_train).
## Your code here
Задание 4. (2 балла) Обучите наивный байесовский классификатор MultinomialNB с параметром alpha=1 на выборке train. Примените его к данным контрольной выборки test и выведите долю верно классифицированных текстов.
Пример использования MultinomialNB (раздел Examples). Данный объект имеет 2 необходимых вам метода:
## Your code here
Задание 5. (1 балл) Обучите наивный байесовский классификатор MultinomialNB с параметром alpha=0 на выборке train. Примените его к данным контрольной выборки test и выведите долю верно классифицированных текстов. Поменяются ли результаты?
## Your code here