import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,8)
# Для кириллицы на графиках
font = {'family': 'Verdana',
'weight': 'normal'}
plt.rc('font', **font)
Формально, дерево решений - это связный ациклический граф. В нем можно выделить 3 типа вершин:
Во внутренней или коневой вершине признак проверяется на некий логический критерий, по результатам которого мы движемся все глубже
{python}
function decision_tree(X, y):
if stopping_criterion(X, y) == True:
S = create_leaf_with_prediction(y)
else:
S = create_node()
(X_1, y_1) .. (X_L, y_L) = best_split(X, y)
for i in 1..L:
C = decision_tree(X_i, y_i)
connect_nodes(S, C)
return S
Пусть $p_k$ - это доля класса $C_k$ в узле дерева $S$.
def plot_impurities():
p = np.linspace(0, 1, 100)
p = np.c_[p, 1-p]
missclass = 1 - p.max(axis=1)
plt.plot(p[:,0], missclass, label = 'missclassification error')
gini = 1 - (p ** 2).sum(axis=1)
plt.plot(p[:,0], gini, label = 'gini index')
entropy = - np.nansum((p*np.log2(p)), axis=1)
plt.plot(p[:,0], entropy, label = 'entropy')
plt.xlabel('$p_k$')
plt.ylabel('$I(S)$')
# plt.legend(loc=2, bbox_to_anchor=(0.,0.))
plt.legend(loc=2, bbox_to_anchor=(-0.3,1))
plot_impurities()
Выберем признак $A$ и пороговое значение $t$ на нем таким образом, чтобы уменьшить неопределенность:
Насколько уменьшится неопределенность:
$$ Gain(S, A) = I(S) - \left(\frac{|S_L|}{|S|}\cdot I(S_L) + \frac{|S_R|}{|S|}\cdot I(S_R) \right),$$ где $S_R$ и $S_L$ - это потомки узла $S$ c объектами, удовлетворяющим соответствующим условиям.
Замечания:
Воспользуемся данными про вино, которые мы видели в ДЗ№0
Имплементируйте понравившаюся вам меру неопределенности и посмотрите, где будет находится оптимальный порог.
def impurity_measure(p):
# Здесь надо внести исправления
# Выберите меру неопределенности и имплементируйте ее
# Так как у нас задача классификации на 2 класса, то p - это массив из двух значений
return 0
def wine_demo():
# Данные
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv', sep=';')
# Рисовалка
fig, ax = plt.subplots(1, 2)
fig.set_figheight(5)
# Заменяем целевую переменную на класс (хорошее-плохое вино)
df_wine.loc[:, 'quality_cat'] = (df_wine.loc[:, 'quality'] > 5).astype(int)
idx = df_wine.loc[:, 'quality_cat'] == 1
df_wine.loc[idx, 'alcohol'].hist(label='good quality', bins=20, alpha = 0.4, ax=ax[0])
df_wine.loc[~idx, 'alcohol'].hist(label='bad quality', bins=20, alpha = 0.4, ax=ax[0])
ax[0].set_xlabel('alcohol')
#
p = np.array([df_wine.quality_cat.mean(), 1-df_wine.quality_cat.mean()])
init_impurity = impurity_measure(p)
# Зададим значения порогов
t_range = np.linspace(df_wine.alcohol.min(), df_wine.alcohol.max(), 100)
# В этом списке будут хранится величины Gain для каждого порога
G = []
for t in t_range:
idx = df_wine.alcohol < t
p1 = np.array([df_wine.loc[idx, 'quality_cat'].mean(), 1-df_wine.loc[idx, 'quality_cat'].mean()])
p2 = np.array([df_wine.loc[~idx, 'quality_cat'].mean(), 1-df_wine.loc[~idx, 'quality_cat'].mean()])
#
G.append(init_impurity - (idx.mean()*impurity_measure(p1) + (1-idx.mean())*impurity_measure(p2)))
ax[1].plot(t_range, G)
ax[1].set_xlabel('alcohol')
ax[1].set_ylabel('Gain')
mG = np.nanmax(G)
mt = t_range[np.nanargmax(G)]
ax[0].vlines(mt, 0, 150, label='best threshold (%.2f)' % mt)
ax[1].vlines(mt, 0, mG, label='best threshold\n(gain = %.4f)' % mG)
ax[0].legend()
ax[1].legend()
wine_demo()
Для того, чтобы демо полностью работало, вам надо установить пакет для визуализации графов graphviz
. Если у вас его еще нет, но вы захотите видеть такие картинки - сделайте это, пожалуйста, дома.
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
from ipywidgets import interact, IntSlider
import subprocess
def demo_dec_tree(depth=1):
fig, ax = plt.subplots(1,2)
fig.set_figheight(5)
np.random.seed(0)
C = np.array([[0., -0.7], [1.5, 0.7]])
gauss1 = np.dot(np.random.randn(200, 2) + np.array([4, 2]), C)
gauss2 = np.dot(np.random.randn(300, 2), C)
X = np.vstack([gauss1, gauss2])
y = np.r_[np.ones(200), np.zeros(300)]
ax[1].scatter(X[:,0], X[:, 1], c=y)
ax[1].set_xlabel('$x_1$')
ax[1].set_ylabel('$x_2$')
# Dec Tree Stuff
tree = DecisionTreeClassifier(criterion='entropy', max_depth=depth, random_state=123)
tree.fit(X,y)
x_range = np.linspace(X.min(), X.max(), 100)
xx1, xx2 = np.meshgrid(x_range, x_range)
Y = tree.predict(np.c_[xx1.ravel(), xx2.ravel()])
Y = Y.reshape(xx1.shape)
ax[1].contourf(xx1, xx2, Y, alpha=0.3)
ax[1].scatter(X[:,0], X[:,1],c=y)
try:
with open('tree.dot', 'w') as fout:
export_graphviz(tree, out_file=fout, feature_names=['x1', 'x2'], class_names=['0', '1'])
command = ["dot", "-Tpng", "tree.dot", "-o", "tree.png"]
subprocess.check_call(command)
ax[0].imshow(plt.imread('tree.png'))
ax[0].axis("off")
except:
pass
try:
fig = interact(demo_dec_tree, depth=IntSlider(min=1, max=5, value=1))
except:
print 'Что-то не так. Посмотрите на доску'
Для задачи регрессии в качестве меры неопределенности могут выступать
from sklearn.tree import DecisionTreeRegressor
x_true = np.arange(-5, 5, 0.2)
x = x_true + np.random.rand(x_true.shape[0]) - 0.5
y_true = np.sin(x_true)+x_true/3
y = y_true + np.random.rand(x_true.shape[0]) - 0.5
def plot_dec_reg(depth=1, criterion='mse', ):
fig, ax = plt.subplots(1,2)
fig.set_figheight(5)
tree = DecisionTreeRegressor(criterion=criterion, max_depth=depth)
tree.fit(x.reshape(-1,1), y)
y_hat = tree.predict(x_true.reshape(-1,1))
ax[1].plot(x_true, y_true, c='g', label='$f(x)$')
ax[1].scatter(x, y, label='actual data')
ax[1].set_xlabel('x_1')
ax[1].set_ylabel('y')
ax[1].plot(x_true, y_hat, c='r', label='decision tree \nregression')
ax[1].legend(loc=2)
try:
with open('tree.dot', 'w') as fout:
export_graphviz(tree, out_file=fout, feature_names=['x1', 'x2'], class_names=['0', '1'])
command = ["dot", "-Tpng", "tree.dot", "-o", "tree.png"]
subprocess.check_call(command)
ax[0].imshow(plt.imread('tree.png'))
ax[0].axis("off")
except:
pass
try:
fig = interact(plot_dec_reg, depth=IntSlider(min=1, max=5, value=1), criterion=['mse', 'mae'])
except:
print 'Что-то не так. Посмотрите на доску'
Загрузите файл с данными.
Представьте, что вы отвечаете за продвижение детских товаров в одном из магазинов некоторой ритейловой сети. Это значит, что вам нужно сделать так, чтобы подгузники, питательные смеси, соски, игрульки, коляски, манежи и прочией товары, расходились как можно лучше.
Из исследований фокус-группы вы выяснили, что молодые родители привыкают к брендам тех или иных детских товаров довольно быстро. Вам бы хотелось, чтобы потенциальным покупателям понравилось именно в вашем магазине - можно дать им скидку заранее и обеспечить первое место в их списке магазинов. Вот только как определить, что родители ждут ребенка?
Нужна модель!
df_retail = pd.read_csv('Retail.csv', sep=';')
df_retail.head()
from sklearn.cross_validation import train_test_split
# Your Code Here
from sklearn.cross_validation import cross_val_score
try:
from sklearn.model_selection import validation_curve
except ImportError:
from sklearn.learning_curve import validation_curve
# Your Code Here
В деревьях решений производится автоматический отбор признаков.
Пусть $v(S)$ - это признак, который использовался для ветвления в узле $S$
$$ \text{imp}(A) = \sum\limits_{i: v(S_i) = A} \frac{|S_i|}{|S|} Gain(S_i, A) $$model.feature_importances_
# Your Code Here
# Your Code Here
Bagging - это параллельный способ построения ансамбля.
Вопрос: Какая доля объектов в среднем попадает в один bootstrap сэмпл?
Так же есть некоторые обобщения этого подхода:
В данном случае, на каждом сэмпле базовой моделью является дерево решений.
Если вам нужно за минимальное время построить достаточно точную и устойчивую модель - это ваш вариант.
from sklearn.ensemble import RandomForestClassifier
# Your Code Here