1、决策树
招聘机器学习算法工程师的时候,往往会对应聘者的条件进行筛选,如图所示,叶子结点是根据已知的信息做出的决策,该决策树的深度为3
- 决策树是非参数学习算法
- 可以解决多分类问题
- 也可以解决回归问题(通过得到的叶子结点的那一类的数据的平均值预测最终得值)
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris=datasets.load_iris()
x=iris.data[:,2:]
y=iris.target
print(y)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.scatter(x[y==2,0],x[y==2,1])
plt.show()
from sklearn.tree import DecisionTreeClassifier
tree=DecisionTreeClassifier(max_depth=5,criterion='entropy') #最高深度,熵
tree.fit(x,y)
def plot_tree(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(-1, 1)
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_map=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,linewidth=5,cmap=custom_map)
plot_tree(tree,axis=[0.5,7.5,0,3])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.scatter(x[y==2,0],x[y==2,1])
plt.show()
2、信息熵和基尼系数
(1)信息熵:
我们通过决策树进行分类的时候,会产生很多的分类节点,这些节点都是判断条件,在进行分类前我们需要得到两类信息:1、每个节点在哪个维度做划分。2、划分的值是多少。
信息熵:
熵在信息论中代表随机变量不确定度的度量
熵越大,数据的不确定性越高;熵越小,数据的不确定度越低
公式:
H
=
−
∑
i
=
1
k
p
i
l
o
g
(
p
i
)
H=-\sum_{i=1}^{k}p_{i}log\left ( p_{i} \right )
H=−∑i=1kpilog(pi)
一个系统中有k类信息,每个信息的信息量的比例为
p
i
p_{i}
pi。
举例:有三类数据,分别占比为{1/10 , 2/10 , 7/10},信息熵为0.8018
有三类,分别占比为{0,0,1},信息熵为0 。由此可见第二例中全为第三类,所以是最确定的,所以信息熵最低。
目的:找到某一种划分,使得划分后信息熵降低
(2)基尼系数
公式:
G
=
1
−
∑
i
=
1
k
p
i
2
G=1-\sum_{i=1}^{k}p_{i}^{2}
G=1−∑i=1kpi2
性质:和信息熵一样,基尼系数越小,数据越确定,基尼系数越高,数据的不确定度越高。
(3)信息熵vs基尼系数
- 熵的计算比基尼系数的计算慢
- sklearn中默认为基尼系数
- 大多数时候二者没有特别的效果优劣
3、sklearn使用决策树
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris=datasets.make_moons()
x,y=datasets.make_moons(noise=0.25,random_state=666)
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
from sklearn.tree import DecisionTreeClassifier
dt_tree=DecisionTreeClassifier() #如果不定义超参数,则决策树会一直向下划分,直到基尼系数都为0
dt_tree.fit(x,y)
def plot_tree(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 100)).reshape(-1, 1)
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_map=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0,x1,zz,linewidth=5,cmap=custom_map)
plot_tree(dt_tree,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
在这个决策树分类器中,不使用任何的超参数,则分类器默认将决策树一直向下划分,直到所有的基尼系数都为0。由下图可以看出此分类过拟合了。
(1)在分类器中传入超参数max_depth=2(规定树的深度为2)
dt_tree2=DecisionTreeClassifier(max_depth=2)
dt_tree2.fit(x,y)
plot_tree(dt_tree2,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
可以看到没有发生过拟合,并且可能发生了欠拟合。
(2)再传入另一个超参数min_samples_split=10,表示对于一个节点来说,至少需要多少个样本数据才会继续划分下去。
dt_tree3=DecisionTreeClassifier(min_samples_split=10)
dt_tree3.fit(x,y)
plot_tree(dt_tree3,axis=[-1.5,2.5,-1.0,1.5])
plt.scatter(x[y==0,0],x[y==0,1])
plt.scatter(x[y==1,0],x[y==1,1])
plt.show()
由上图可以看出,该超参数能有效改善过拟合,该超参数数值越高越不容易发生过拟合,当然数值太高会发生欠拟合。
(3)第三个输入的超参数是min_samples_leaf=6,表示叶子结点至少应该有几个样本。如果数值越少,则对该数据越敏感,越容易发生过拟合。
dt_tree4=DecisionTreeClassifier(min_samples_leaf=6)
(4)第四个超参数是max_leaf_nodes=4,表示最多有多少个叶子结点,叶子结点越多,模型越复杂,越容易发生过拟合。
dt_tree5=DecisionTreeClassifier(max_leaf_nodes=4)
可以通过网格搜索的方式,找到这些超参数之间的平衡关系,并找到最好的一个组合。
4、决策树解决回归问题
from sklearn import datasets
boston=datasets.load_boston()
x=boston.data
y=boston.target
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666)
#加载决策树的回归模型
from sklearn.tree import DecisionTreeRegressor
dt_reg=DecisionTreeRegressor()
dt_reg.fit(x_train,y_train)
print(dt_reg.score(x_test,y_test))
print(dt_reg.score(x_train,y_train))
输出为:
0.58304453845759
1.0
可以看出该模型对训练集的得分为1,对测试集的得分很低,很明显的过拟合现象。需要改变超参数来减少过拟合现象。
5、决策树的局限性
- 决策边界都是与坐标轴平行,具有局限性,不能很好的划分类别。
因为边界都是横平竖直,所以就会呈现上面的分类,这样明显是不对的。 - 决策树对个别数据敏感(如果删掉几个数据,可能决策边界就会不同)(非参数学习法的通病)