# 决策树与随机森林

## 决策树

P c = 类 别 c 的 样 本 数 D 中 的 样 本 数 P_{c}=\frac{类别c的样本数}{D中的样本数} X X 是类别

I G ( X ∣ A ) = H ( X ) − ( ∣ D 1 ∣ ∣ D ∣ H ( X ∣ A = Y e s ) + ∣ D 2 ∣ ∣ D ∣ H ( X ∣ A = N o ) ) IG(X|A)=H(X)-(\frac{|D_{1}|}{|D|}H(X|A=Yes)+\frac{|D_{2}|}{|D|}H(X|A=No))

## 基尼系数

CART决策树使用基尼系数（Gini index）来选择划分属性。数据集的纯度可用基尼值来衡量： G i n i ( D ) = ∑ k = 1 ∣ Y ∣ ∑ k ′ ≠ k p k p k ′ = 1 − ∑ k = 1 ∣ Y ∣ p k 2 Gini(D)=\sum_{k=1}^{|\mathcal Y|}\sum_{k^{&#x27;}\neq k}p_{k}p_{k^{&#x27;}}=1-\sum_{k=1}^{|\mathcal Y|}p_{k}^{2}
Gini(D)反映了从数据集D中先后随机抽取两个样本，其类别标志不一致的概率。因此Gini(D)越小，数据集D的纯度越高。

## scikit-learn构建决策树

from sklearn import datasets
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt

def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])

x1_min, x1_max = X[:, 0].min()-1, X[:, 0].max()+1
x2_min, x2_max = X[:, 1].min()-1, X[:, 1].max()+1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))

z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
z = z.reshape(xx1.shape)
plt.contourf(xx1, xx2, z, alpha=0.4, cmap=cmap)
plt.xlim((x1_min, x1_max))
plt.ylim((x2_min, x2_max))

for idx, cl in enumerate(np.unique(y)):
plt.scatter(X[y == cl, 0], X[y == cl, 1],
alpha=0.8, c=cmap(idx),
marker=markers[idx], label=cl)

if test_idx:
plt.scatter(X[test_idx, 0], X[test_idx, 1], c='',
alpha=1.0, linewidth=1, marker='o',
edgecolors='k', s=55, label='test set')

X =iris.data[:, [2, 3]]
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

tree = DecisionTreeClassifier(criterion='entropy',
max_depth=3,
random_state=0)
tree.fit(X_train, y_train)

X_combined = np.vstack((X_train, X_test))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(X_combined, y_combined, tree, range(105, 150))
plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.show()


sklearn可以将决策树导出为.dot格式的文件，使用pydotplus库可以使得dot文件转换为pdf文件。前提是需要安装并配置好graphviz库。

from sklearn.externals.six import StringIO
from sklearn.tree import export_graphviz
import pydotplus

dot_data = StringIO()
export_graphviz(tree,
out_file=dot_data,
feature_names=['petal length', 'petal width'])
graph = pydotplus.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf('tree.pdf')


## 随机森林（Random Forest）

（1）使用bootstrap抽样随机选择 n n 个样本用于训练（从训练集随机重复放回抽样 n n 个样本）
（2）使用（1）选取的样本构造一棵决策树。不重复地随机选取 d d 个特征，并采用最大化信息增益的方式划分节点。
（3）重复上述过程 M M 次，便产生了 M M 棵决策树。对决策树进行多数投票（majority voting）
bootstrap的抽样数量一般与原始训练集中的样本数量相同，这样会在偏差与方差之间得到权衡。sklearn中默认 d = f e a t u r e s _ n u m d=\sqrt{features\_num} ,其中features_num是特征总量。

from sklearn.ensemble import RandomForestClassifier
forest = RandomForestClassifier(criterion='entropy',
n_estimators=10,
bootstrap=True,
random_state=1)
forest.fit(X_train, y_train)


07-13 1万+
05-16 6236
10-01 3446
04-23 2231
07-24
07-06 6万+
09-02 463
01-22 1413
11-10 1827
09-13 1万+
03-19 1051
07-03 449
01-31 1万+
09-02
04-09 333