决策树是一种常见的机器学习方法,根据上一篇文章中所说的多分类问题。决策树可以对二分类以及多分类进行建模,同时我们还可以得到相应的阈值。
二分类为例进行研究:
举例:当我们判断一个东西他是否是我们所想的事物时,我们会对其进行一系列的阶梯型的判断。如果我们判断男性/女性:
通过对二分类的因变量进行决策和一系列的子决策最终我们会得到一个树。
决策树的结构包括:根节点——内部节点——叶节点
叶节点:对应决策结果
其他节点:对应于一个因变量的测试,同时每个节点包括的样本集合是通过属性的测试结果划分而来的。
根节点包含训练集的全集
三种递归返回的情况:
(1)此节点中所有样本都是同一类别的,无需继续进行决策再划分
(2)所有样本的属性都是相同的,无法通过阈值分离。
方法:我们把当前的这个节点设置为叶节点,并且将其类别设为样本集合中类别最多的类
(3)当前节点中的样本数量为0
方法:把前一个节点设为叶节点。
对于模型而言,我们希望一个节点中尽可能都是同一类别的样本,也就是使得样本纯度尽量大
因此如何度量节点中样本的纯度的问题随之而来。
度量节点中样本纯度:
信息熵度量法:
每一类再样本中的比列为:
上式的值越小则该节点的纯度越大
基尼不纯度:
这个基尼值同样是越小越好,越说明纯度大。
如何选择因变量划分?
假定因变量有M个类别,同时这M个类别。使用
来对训练集进行训练会得到V个节点分支。我们可以根据上面介绍的方法计算信息熵。同时对每个节点赋予权重
(节点中的样本数占总样本数的值)。
信息增益越大,意味着使用属性a来划分所得到的纯度提升越大,即我们通常选择信息增益最大的属性进行划分。
信息增益会对可取值数目较多的属性有所偏好(对于一个因变量它的取值范围越大),为了减少这种因素带来的影响我们会使用增益率划分因变量。
增益率(C4.5决策树算法):
但是增益率同样对于可取值数目较少的有所偏好,所以并不是直接选择增益率最大的因变量,而是先找出增益率高于平均水平的因变量,在选择增益率最高的。
基尼指数(GART决策树算法):
如果运用基尼指数时,我们选择划分后基尼不纯度最小的因变量。
过拟合会发生在任何模型,在决策树中通过见剪枝来解决过拟合问题。
剪枝分为:预剪枝和后剪枝
预剪枝:
生成决策树的过程中,对每个节点在划分前先进行估计,如果该节点的划分不能带来泛化性能的提升,那么停止划分将该节点标记为叶节点。
后剪枝:
先生成决策树然后假设某个节点替换为叶节点能提升模型泛化性能,然后进行验证如果与假设一致就替换为叶节点。(通常优于预剪枝)
连续属性离散化:
当因变量的取值为连续型时,我们要对因变量的值进行处理(连续属性的可取值数目不可数)
二分法:
假定给定集合D和连续属性a,假定a在D上出现了n个取值,我们对取值进行排序。
基于基本划分点t可以将子集划分为,取相邻两个点的中点的集合为代取中卫点,选取最优的划分点进行样本集合的划分。
判别:
我们选则Gain(D,a,t)最大化的划分点。
缺失值处理:
当我们遇到不完整的样本,即样本某些属性有缺失值。我们不能直接放弃这些样本,则会面临两个问题,
(1)如何在属性缺失的情况下进行划分属性选择
(2)给定划分属性,如果该样本在这个属性上有缺失值又当如何。
对于问题(1):
假定用表示D中没有缺失的样本的集合,对于问题一我们可以根据
来判断因变量的优劣性。假定属性a有V个可取值,,令
便是
中在属性a上取值为
的样本子集。
我们为每个样本赋予一个权重,并定义:
于是我们推广信息增益的公式:
对于问题(2):
若样本x在划分属性a上的取值,则x样本划分入对应子节点,且样本权值在子节点中保持,若样本x在划分属性上取值未知,则将此样本x同时划入所有子节点,且样本权值在与属性值
对应的子节点中调整为
(让同一个样本以不同的概率划分到不同的节点中去)。
针对鸢尾花数据集我们展开实战模拟:
下见代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.preprocessing import LabelEncoder
import graphviz
from sklearn.tree import export_graphviz
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
data=pd.read_csv('iris.data',names=['sepal_lengh_cm','sepal_width_cm','petal_length_cm','petal_width_cm','class'],sep=",",skiprows=1)
data.head(5)
data.info()#观察熟属性是否有缺失值
data["class"].hist(bins=50,figsize=(3,2))#查看有多少中分类
class_le=LabelEncoder()#将文本类别转换为数字类别
data["class"]=class_le.fit_transform(data['class'].values)
split = StratifiedShuffleSplit(n_splits=1,test_size=0.2,random_state=42) #划分训练集和测试机
for train_index,test_index in split.split(data.values[:,0:-1],data["class"]):
train_set=data.values[train_index]
test_set=data.values[test_index]
X=train_set[:,0:-1];Y=train_set[:,-1]
model=DecisionTreeClassifier(max_depth=2,criterion="entropy")#超参数max_depth 使用熵作为标准,默认为基尼不纯度
model.fit(X,Y)
dot_data = export_graphviz(model, out_file=None,feature_names= ['sepal_lengh_cm','sepal_width_cm','petal_length_cm','petal_width_cm'],class_names=["0","1","2"],rounded=True,filled=True)
graph = graphviz.Source(dot_data)
graph.render('决策树可视化')
model.predict_proba([data.values[50,0:-1]])#预测样本属于某一类的概率。
scores=cross_val_score(model,train_set[:,0:-1],train_set[:,-1],scoring="neg_mean_squared_error",cv=10)
model_scores=np.sqrt(-scores)
def display_scorrs(scores):
print("Scores:",scores)
print("Mean:",scores.mean())
print("Standard deviation:",scores.std())
display_scorrs(model_scores)
param_grid=[{"max_depth":[2,3,4,5,6]}]
grid_search=GridSearchCV(model,param_grid,scoring="neg_mean_squared_error",return_train_score=True,cv=5)
grid_search.fit(X,Y)
grid_search.best_params_
DecisionTreeClassifier类的其他参数:
min_samples_split#分裂前必须有的最小样本数
min_samples_leaf#叶节点必须有的最小样本数
min_weight_fraction_leaf#同上
max_leaf_nodes#最大叶节点数
max_features#分裂每个评估点的最大特征数
拓展决策树回归: