Задание по программированию: Бэггинг и случайный лес

Загрузите датасет digits с помощью функции load_digits из sklearn.datasets и подготовьте матрицу признаков X и ответы на обучающей выборке y (вам потребуются поля data и target в объекте, который возвращает load_digits).


In [1]:
from sklearn import datasets, tree, cross_validation, ensemble
from sklearn.model_selection import cross_val_score

from math import sqrt

import numpy as np


/home/ubuntuser/anaconda3/lib/python3.6/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
  "This module will be removed in 0.20.", DeprecationWarning)

In [2]:
digits = datasets.load_digits()

In [3]:
X = digits.data
y = digits.target

In [4]:
def write_answer(cross_val_score, file_name):
    with open(file_name, "w") as fout:
        fout.write(str(cross_val_score))

1. Создайте DecisionTreeClassifier с настройками по умолчанию и измерьте качество его работы с помощью cross_val_score. Эта величина и будет ответом в пункте 1.


In [5]:
clf         = tree.DecisionTreeClassifier()
x_val_score = cross_val_score(clf, X, y, cv=10).mean()
write_answer(x_val_score, 'answer_1.txt')
print(x_val_score)


0.828079327353

2. Воспользуйтесь BaggingClassifier из sklearn.ensemble, чтобы обучить бэггинг над DecisionTreeClassifier. Используйте в BaggingClassifier параметры по умолчанию, задав только количество деревьев равным 100.

Качество классификации новой модели - ответ в пункте 2. Обратите внимание, как соотносится качество работы композиции решающих деревьев с качеством работы одного решающего дерева.


In [6]:
bagging_clf = ensemble.BaggingClassifier(clf, n_estimators=100)
x_val_score = cross_val_score(bagging_clf, X, y, cv=10).mean()
write_answer(x_val_score, 'answer_2.txt')
print(x_val_score)


0.923286042709

3. Теперь изучите параметры BaggingClassifier и выберите их такими, чтобы каждый базовый алгоритм обучался не на всех d признаках, а на $\sqrt d$ случайных признаков. Качество работы получившегося классификатора - ответ в пункте 3. Корень из числа признаков - часто используемая эвристика в задачах классификации, в задачах регрессии же часто берут число признаков, деленное на три. Но в общем случае ничто не мешает вам выбирать любое другое число случайных признаков.


In [7]:
stoch_train_len = int(sqrt(X.shape[1]))

bagging_clf = ensemble.BaggingClassifier(clf, n_estimators=100, max_features=stoch_train_len)
x_val_score = cross_val_score(bagging_clf, X, y, cv=10).mean()
write_answer(x_val_score, 'answer_3.txt')
print(x_val_score)


0.933257902152

4. Наконец, давайте попробуем выбирать случайные признаки не один раз на все дерево, а при построении каждой вершины дерева. Сделать это несложно: нужно убрать выбор случайного подмножества признаков в BaggingClassifier и добавить его в DecisionTreeClassifier. Какой параметр за это отвечает, можно понять из документации sklearn, либо просто попробовать угадать (скорее всего, у вас сразу получится). Попробуйте выбирать опять же $\sqrt d$ признаков. Качество полученного классификатора на контрольной выборке и будет ответом в пункте 4.


In [8]:
stoch_clf       = tree.DecisionTreeClassifier(max_features=stoch_train_len)
bagging_clf     = ensemble.BaggingClassifier(stoch_clf, n_estimators=100)
x_val_score_own = cross_val_score(bagging_clf, X, y, cv=10).mean()
write_answer(x_val_score_own, 'answer_4.txt')
print(x_val_score)


0.933257902152

5. Полученный в пункте 4 классификатор - бэггинг на рандомизированных деревьях (в которых при построении каждой вершины выбирается случайное подмножество признаков и разбиение ищется только по ним). Это в точности соответствует алгоритму Random Forest, поэтому почему бы не сравнить качество работы классификатора с RandomForestClassifier из sklearn.ensemble. Сделайте это, а затем изучите, как качество классификации на данном датасете зависит от количества деревьев, количества признаков, выбираемых при построении каждой вершины дерева, а также ограничений на глубину дерева. Для наглядности лучше построить графики зависимости качества от значений параметров, но для сдачи задания это делать не обязательно.


In [9]:
random_forest_clf = ensemble.RandomForestClassifier(random_state=stoch_train_len, n_estimators=100)
x_val_score_lib   = cross_val_score(random_forest_clf, X, y, cv=10).mean()
print(x_val_score_lib)


0.952739958798

In [10]:
answers = '2 3 4 7'
write_answer(answers, 'answer_5.txt')