ID3---最大信息增益
在信息论与概率统计中,熵(entropy)是表示随机变量不确定性的度量,设X是一个取有限个值的随机变量,其概率分布为:\[P(X=X_i)=P_i (i = 1,2,...,n)\],则随机变量X的熵定义为:\[H(X) = -\sum_{i=1}^np_i\log{p_i}\]表达式中的对数以2为底或以e为底,这时熵的单位分别称作bit或nat,从表达式可以看出X的熵与X的取值无关,所以X的熵也记作\(H(p)\),即\[H(p) = -\sum_{x=1}^np_i\log{p_i}\]熵取值越大,随机变量的不确定性越大
条件熵:
条件熵H(Y|X)表示在已知随机变量X的条件下,随机变量Y的不确定性,随机变量X给定的条件下随机变量Y的条件熵定义为X给定条件下Y的条件概率分布的熵对X的数学期望\[H(Y|X) = \sum_{i=1}^nP(X=X_i)H(Y|X=X_i)\]
信息增益:\[g(D,A) = H(D) - H(D|A)\]
import pandas as pd
data = {
'年龄':['老','年轻','年轻','年轻','年轻'],
'长相':['帅','一般','丑','一般','一般'],
'工资':['高','中等','高','高','低'],
'写代码':['不会','会','不会','会','不会'],
'类别':['不见','见','不见','见','不见']}
frame = pd.DataFrame(data,index=['小A','小B','小C','小D','小L'])
print(frame)
年龄 长相 工资 写代码 类别
小A 老 帅 高 不会 不见
小B 年轻 一般 中等 会 见
小C 年轻 丑 高 不会 不见
小D 年轻 一般 高 会 见
小L 年轻 一般 低 不会 不见
import math
print(math.log(3/5))
print('H(D):',-3/5 *math.log(3/5,2) - 2/5*math.log(2/5,2))
print('H(D|年龄)',1/5*math.log(1,2)+4/5*(-1/2*math.log(1/2,2)-1/2*math.log(1/2,2)))
print('以同样的方法计算H(D|长相),H(D|工资),H(D|写代码)')
print('H(D|长相)',0.551)
print('H(D|工资)',0.551)
print('H(D|写代码)',0)
-0.5108256237659907
H(D): 0.9709505944546686
H(D|年龄) 0.8
以同样的方法计算H(D|长相),H(D|工资),H(D|写代码)
H(D|长相) 0.551
H(D|工资) 0.551
H(D|写代码) 0
计算信息增益:g(D,写代码)=0.971最大,可以先按照写代码来拆分决策树
C4.5---最大信息增益比
以信息增益作为划分训练数据集的特征,存在偏向于选择取值较多的问题,使用信息增益比可以对对着问题进行校正,这是特征选择的另一标准
信息增益比定义为其信息增益g(D,A)与训练数据集D关于特征A的值的熵\(H_A(D)\)之比:\[g_R(D,A) = \frac{g(D,A)}{H_A(D)}\]
\[H_A(D) = -\sum_{i=1}^n\frac{|D_i|}{|D|}\log\frac{|D_i|}{|D|}\]
拿上面ID3的例子说明:
\[H_年龄(D) = -1/5*math.log(1/5,2)-4/5*math.log(4/5,2)\]
\[g_R(D,年龄) = H_{年龄}(D)/g(D,年龄) = 0.171/0.722 = 0.236 \]
CART----最大基尼指数(Gini)
Gini描述的是数据的纯度,与信息熵含义类似,分类问题中,假设有K个类,样本点数据第k类的概率为\(P_k\),则概率分布的基尼指数定义为:
\[Gini(p) = 1- \sum_{k=1}^Kp_k(1-p_k) = 1 - \sum_{k=1}^Kp_{k}^2\]
对于二分类问题,弱样本点属于第1个类的概率是p,则概率分布的基尼指数为\[Gini(p) = 2p(1-p)\],对于给定的样本几何D,其基尼指数为\[Gini(D) = 1 - \sum_{k=1}^K[\frac{|C_k|}{|D|}]^2\]注意这里\(C_k\)是D种属于第k类的样本子集,K是类的个数,如果样本几个D根据特征A是否取某一可能指a被分割成D1和D2两部分,则在特征A的条件下,集合D的基尼指数定义为\[Gini(D,A) = \frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2)\]
\[Gini(D|年龄=老)=1/5*(1-1)+4/5*[1-(1/2*1/2+1/2*1/2)] = 0.4\]
CART在每一次迭代种选择基尼指数最小的特征及其对应的切分点进行分类
ID3、C4.5与Gini的区别
从样本类型角度
从样本类型角度,ID3只能处理离散型变量,而C4.5和CART都处理连续性变量,C4.5处理连续性变量时,通过对数据排序之后找到类别不同的分割线作为切割点,根据切分点把连续型数学转换为bool型,从而将连续型变量转换多个取值区间的离散型变量。而对于CART,由于其构建时每次都会对特征进行二值划分,因此可以很好地适合连续性变量。
从应用角度
ID3和C4.5只适用于分类任务,而CART既可以用于分类也可以用于回归
从实现细节、优化等角度
ID3对样本特征缺失值比较敏感,而C4.5和CART可以对缺失值进行不同方式的处理,ID3和C4.5可以在每个结点熵产生出多叉分支,且每个特征在层级之间不会复用,而CART每个结点只会产生两个分支,因此会形成一颗二叉树,且每个特征可以被重复使用;ID3和C4.5通过剪枝来权衡树的准确性和泛化能力,而CART直接利用全部数据发现所有可能的树结构进行对比。
为卫星数据集训练并微调一个决策树
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.tree import DecisionTreeClassifier
#获取数据集
x,y = make_moons(n_samples=10000,noise=0.4)
#拆分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.2,random_state = 42)
print(len(x_train),len(x_test))
8000 2000
#使用交叉验证的网格搜索获取最佳模型参数
param_grid = {'max_leaf_nodes':list(range(2,100)),'min_samples_split':[2,3,4]}
dts_cfg = DecisionTreeClassifier(random_state=42)
gridsearch = GridSearchCV(dts_cfg,param_grid,n_jobs=-1,verbose=1,cv =3)
gridsearch.fit(x_train,y_train)
Fitting 3 folds for each of 294 candidates, totalling 882 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 8 concurrent workers.
[Parallel(n_jobs=-1)]: Done 34 tasks | elapsed: 2.2s
[Parallel(n_jobs=-1)]: Done 882 out of 882 | elapsed: 4.3s finished
GridSearchCV(cv=3, error_score='raise-deprecating',
estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort=False, random_state=42,
splitter='best'),
fit_params=None, iid='warn', n_jobs=-1,
param_grid={'max_leaf_nodes': [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99], 'min_samples_split': [2, 3, 4]},
pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
scoring=None, verbose=1)
gridsearch.best_estimator_
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
max_features=None, max_leaf_nodes=4, min_impurity_decrease=0.0,
min_impurity_split=None, min_samples_leaf=1,
min_samples_split=2, min_weight_fraction_leaf=0.0,
presort=False, random_state=42, splitter='best')
from sklearn.metrics import accuracy_score
y_test_pred = gridsearch.predict(x_test)
accuracy_score(y_test,y_test_pred)
0.8635
from sklearn.model_selection import ShuffleSplit
n_trees = 1000
n_instances = 100
mini_sets = []
ss = ShuffleSplit(n_splits=n_trees,test_size=len(x_train)- n_instances,random_state = 42)
for mini_train_index,mini_test_index in ss.split(x_train):
x_mini_train = x_train[mini_train_index]
y_mini_train = y_train[mini_train_index]
mini_sets.append((x_mini_train,y_mini_train))
from sklearn.base import clone
import numpy as np
forest = [clone(gridsearch.best_estimator_) for _ in range(n_trees)]
accuracy_scores = []
for tree,(x_mini_train,y_mini_train) in zip(forest,mini_sets):
tree.fit(x_mini_train,y_mini_train)
y_pred = tree.predict(x_test)
accuracy_scores.append(accuracy_score(y_test,y_pred))
np.mean(accuracy_scores)
0.8284495000000001
对于每个测试集实例,生成1000个决策树的预测,并只保留最频繁的预测(您可以为此使用SciPy的mode()函数)。这给出了测试集的多数投票预测
y_pred = np.empty([n_trees, len(x_test)], dtype=np.uint8)
for tree_index, tree in enumerate(forest):
y_pred[tree_index] = tree.predict(x_test)
from scipy.stats import mode
y_pred_majority_votes, n_votes = mode(y_pred, axis=0)
accuracy_score(y_test, y_pred_majority_votes.reshape([-1]))
0.863