目录
决策分类树
2.1 ID3算法(信息增益)
2.2 C4.5 算法(信息增益率)
2.3 CART算法(Gini系数)
CART构造决策树实例
决策树的剪枝
sklearn实现决策树
决策树的调参
银行借贷欺诈检测案例
训练模型
调优及可视化
ID3是决策树学习算法中最具有影响和最为典型的算法,它的基本思想是,利用信息熵的原理,选择信息增益最大的属性作为分类属性。
ID3算法在分类时选择信息熵下降最快的类别作为分类依据
C4.5算法是ID3算法的拓展,它继承了ID3算法的优点并对ID3算法进行了改进和补充。
C4.5算法采用信息增益率作为选择分支属性的标准,克服了ID3算法中信息增益选择属性时偏向选择取值多的属性的不足
基尼指数代表了模型的不纯度,基尼系数越小,不纯度越低,特征越好。这和信息增益(率)正好相反。
基尼指数反映了从数据集中随机抽取两个样本,其类别标记不一致的概率。因此基尼指数越小,则数据集纯度越高。基尼指数偏向于特征值较多的特征,类似信息增益。基尼指数可以用来度量任何不均匀分布,是介于 0~1 之间的数,0 是完全相等,1 是完全不相等。
CART算法处理分类问题时,以叶子节点上样本投票预测类别,处理回归问题时,以叶子节点的样本均值作为预测值
ID | 有房者 | 婚姻 | 年收入 | 拖欠贷款者 |
1 | 是 | 单身 | 125k | 否 |
2 | 否 | 已婚 | 100k | 否 |
3 | 否 | 单身 | 70k | 否 |
4 | 是 | 已婚 | 120k | 否 |
5 | 否 | 离异 | 95k | 是 |
6 | 否 | 已婚 | 60k | 否 |
7 | 是 | 离异 | 220k | 否 |
8 | 否 | 单身 | 85k | 是 |
9 | 否 | 已婚 | 75k | 否 |
10 | 否 | 单身 | 90k | 是 |
构造一颗决策树:
首先选择一个根节点 (Gini)
同理:婚姻Gini加权 = 3/10,年收入Gini加权= 5/14
婚姻Gini加权最小,所以选择婚姻作为根节点
剪枝参数(提高决策树的泛化性)
决策树不加限制,会生长到衡量不纯度的指标最优,或者没有更多特征可用,这样的决策树会过拟合。当决策树对训练数据有过于优秀的解释性,它必然包含了训练样本中的噪声,并且对未知数据的拟合程度不足
限制分枝时考虑的特征个数max_features,超过限制个数的特征都会被舍弃。用来限制高维度数据的过拟合的剪枝参数
限制信息增益的大小min_impurity_decrease,信息增益小于设定数值的分枝不会发生。
叶子结点越多,损失越大
import pandas as pd
import graphviz
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
wine = load_wine()
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis = 1)
X_train,X_test,y_train,y_test = train_test_split(wine.data,wine.target,test_size = 0.3)
clf = DecisionTreeClassifier(criterion = 'entropy',random_state = 30,splitter = 'random')
clf.fit(X_train,y_train)
score = clf.score(X_test,y_test)
score
#决策树可视化
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
dot_data = tree.export_graphviz(clf,out_file = None,feature_names= feature_name,
class_names=["琴酒","雪莉","贝尔摩德"],
filled=True,
rounded = True)
graph = graphviz.Source(dot_data)
graph
#查看特征重要性
# zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
[*zip(feature_name,clf.feature_importances_)]
'''[('酒精', 0.31494660642254896),
('苹果酸', 0.0),
('灰', 0.05724939731598719),
('灰的碱性', 0.06405387911775662),
('镁', 0.0),
('总酚', 0.010518365863640303),
('类黄酮', 0.4249255550082155),
('非黄烷类酚类', 0.01898375957316527),
('花青素', 0.0),
('颜色强度', 0.0),
('色调', 0.0),
('od280/od315稀释葡萄酒', 0.10932243669868624),
('脯氨酸', 0.0)]'''
score_train = clf.score(X_train,y_train)
score_train
#剪枝参数(提高决策树的泛化)
# 决策树不加限制,会生长到衡量不纯度的指标最优,或者没有更多特征可用,这样的决策树会过拟合
# 当决策树对训练数据有过于优秀的解释性,它必然包含了训练样本中的噪声,并且对未知数据的拟合程度不足
clf = DecisionTreeClassifier(criterion = 'entropy',random_state = 20,splitter = 'random',
max_depth = 4,
min_samples_split =9,
# min_samples_leaf = 10
)
clf = clf.fit(X_train,y_train)
clf.score(X_test,y_test)
#0.8333333333333334
#确认最优的剪枝参数,限制树的深度max_depth
import matplotlib.pyplot as plt
test = []
for i in range(10):#0~9
clf = DecisionTreeClassifier(criterion = 'entropy',
random_state = 20,
splitter = 'random',
max_depth = i+1)
clf = clf.fit(X_train,y_train)
score = clf.score(X_test,y_test)
test.append(score)
plt.plot(range(1,11),test,color = 'red',label = 'max_depth')
plt.xlabel('max_depth')
plt.ylabel('score')
plt.legend()
plt.show()
#根据图像可知最佳max_depth = 4
clf.predict(X_test)#返回每个测试样本的分类/回归结果
clf.apply(X_test)#返回每个测试样本所在的叶子结点的索引
数据集:
链接:https://pan.baidu.com/s/14Bfo1sKhoGoXAAz8fGWzNQ?pwd=lq03
提取码:lq03
# 导入库
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics
from IPython.display import Image
import pydotplus
from sklearn import tree
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import GridSearchCV
import warnings
warnings.filterwarnings("ignore")
# sep=‘\s+‘ 这是正则表达式,通过一定规则的表达式来匹配字符串用的
# \s 表示空白字符,包括但不限于空格、回车(\r)、换行(\n)、tab或者叫水平制表符(\t)等,这个根据编码格式不同代表的含义也不一样,感兴趣可以搜索看一下
# + 是重复修饰符,表示它前面与它紧邻的表达式格式相匹配的字符串至少出现一个,上不封顶
# \s+ 意思就是至少有一个空白符存在
data = pd.read_csv('loan_data 银行借贷决策树.txt',sep='\s+',encoding='utf-8',index_col='nameid')
data.head()
data.columns
x = data.drop(['approve'],axis = 1).values
y = data['approve'].values
print(x.shape,y.shape)
x1 = x[:900]
y1 = y[:900]
x2 = x[900:]
y2 = y[900:]
x_train,x_test,y_train,y_test = train_test_split(x1,y1,test_size = 0.2)
clf = DecisionTreeClassifier()
clf.fit(x_train,y_train)
y_pred = clf.predict(x_test)
print('训练集评分:', clf.score(x_train,y_train))
print('验证集评分:', clf.score(x_test,y_test))
print('测试集评分', clf.score(x2,y2))
print("查准率:", metrics.precision_score(y_test,y_pred))
print('召回率:',metrics.recall_score(y_test,y_pred))
print('f1分数:', metrics.f1_score(y_test,y_pred))
'''训练集评分: 1.0
验证集评分: 0.7277777777777777
测试集评分 0.82
查准率: 0.8173913043478261
召回率: 0.7704918032786885
f1分数: 0.7932489451476794'''
#网格搜索最优参数
param = {'max_depth':[3,5,8],'min_samples_leaf':np.arange(3,10,1),'min_impurity_split':np.linspace(0.1,0.6,10),}
clf = GridSearchCV(DecisionTreeClassifier(),param_grid = param,cv = 8)
clf.fit(x_train,y_train)
print(clf.best_params_,clf.best_score_)
print(confusion_matrix(y_true = y_test,y_pred = y_pred,labels = list(set(y))))#list(set())对原列表去重并按从小到大排序
print(metrics.classification_report(y_test,y_pred ,labels = list(set(y))))
#将网格搜索出来的最优参数代入模型重新训练
clf = DecisionTreeClassifier(max_depth = 5,min_samples_leaf = 4,min_impurity_split = 0.322)
clf.fit(x_train,y_train)
y_pred = clf.predict(x_test)
print('训练集评分:', clf.score(x_train,y_train))
print('验证集评分:', clf.score(x_test,y_test))
print('测试集评分', clf.score(x2,y2))
print("查准率:", metrics.precision_score(y_test,y_pred))
print('召回率:',metrics.recall_score(y_test,y_pred))
print('f1分数:', metrics.f1_score(y_test,y_pred))
'''训练集评分: 0.8347222222222223
验证集评分: 0.8555555555555555
测试集评分 0.99
查准率: 0.8287671232876712
召回率: 0.9918032786885246
f1分数: 0.9029850746268656'''
print(confusion_matrix(y_true = y_test,y_pred = y_pred,labels = list(set(y))))#list(set())对原列表去重并按从小到大排序
print(metrics.classification_report(y_test,y_pred ,labels = list(set(y))))
import graphviz
dot_data = tree.export_graphviz(clf,out_file = None,
feature_names = data.columns[:-1],
class_names = data.columns[-1],
filled = True,
rounded = True,
special_characters = True)
graph = graphviz.Source(dot_data)
graph
from sklearn.datasets import load_iris
from sklearn import tree
import graphviz
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
clf = DecisionTreeClassifier()
clf = clf.fit(iris.data,iris.target)
dot_data = tree.export_graphviz(clf ,out_file = None)
graph = graphviz.Source(dot_data)
graph .render('iris')